diff --git a/.NCrunch_eSuite/eSuite.crunchsolution.cache b/.NCrunch_eSuite/eSuite.crunchsolution.cache new file mode 100644 index 0000000..ad7d9f6 Binary files /dev/null and b/.NCrunch_eSuite/eSuite.crunchsolution.cache differ diff --git a/.NCrunch_eSuite/eSuite.executiontimes.cache b/.NCrunch_eSuite/eSuite.executiontimes.cache new file mode 100644 index 0000000..4631fe4 Binary files /dev/null and b/.NCrunch_eSuite/eSuite.executiontimes.cache differ diff --git a/.vs/ProjectEvaluation/esuite.metadata.v10.bin b/.vs/ProjectEvaluation/esuite.metadata.v10.bin new file mode 100644 index 0000000..600da39 Binary files /dev/null and b/.vs/ProjectEvaluation/esuite.metadata.v10.bin differ diff --git a/.vs/ProjectEvaluation/esuite.projects.v10.bin b/.vs/ProjectEvaluation/esuite.projects.v10.bin new file mode 100644 index 0000000..a58c798 Binary files /dev/null and b/.vs/ProjectEvaluation/esuite.projects.v10.bin differ diff --git a/.vs/ProjectEvaluation/esuite.strings.v10.bin b/.vs/ProjectEvaluation/esuite.strings.v10.bin new file mode 100644 index 0000000..0d28237 Binary files /dev/null and b/.vs/ProjectEvaluation/esuite.strings.v10.bin differ diff --git a/.vs/eSuite/CopilotIndices/18.0.988.22099/CodeChunks.db b/.vs/eSuite/CopilotIndices/18.0.988.22099/CodeChunks.db new file mode 100644 index 0000000..6708eb4 Binary files /dev/null and b/.vs/eSuite/CopilotIndices/18.0.988.22099/CodeChunks.db differ diff --git a/.vs/eSuite/CopilotIndices/18.0.988.22099/SemanticSymbols.db b/.vs/eSuite/CopilotIndices/18.0.988.22099/SemanticSymbols.db new file mode 100644 index 0000000..90a7159 Binary files /dev/null and b/.vs/eSuite/CopilotIndices/18.0.988.22099/SemanticSymbols.db differ diff --git a/.vs/eSuite/DesignTimeBuild/.dtbcache.v2 b/.vs/eSuite/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000..4683094 Binary files /dev/null and b/.vs/eSuite/DesignTimeBuild/.dtbcache.v2 differ diff --git a/.vs/eSuite/FileContentIndex/084c3388-9459-4b64-b472-d52df81fefbb.vsidx b/.vs/eSuite/FileContentIndex/084c3388-9459-4b64-b472-d52df81fefbb.vsidx new file mode 100644 index 0000000..6881975 Binary files /dev/null and b/.vs/eSuite/FileContentIndex/084c3388-9459-4b64-b472-d52df81fefbb.vsidx differ diff --git a/.vs/eSuite/FileContentIndex/7b28d0da-76fd-4119-b37b-9863283bedf3.vsidx b/.vs/eSuite/FileContentIndex/7b28d0da-76fd-4119-b37b-9863283bedf3.vsidx new file mode 100644 index 0000000..5847147 Binary files /dev/null and b/.vs/eSuite/FileContentIndex/7b28d0da-76fd-4119-b37b-9863283bedf3.vsidx differ diff --git a/.vs/eSuite/FileContentIndex/ba823400-7c98-442e-8024-593cd4d5fef1.vsidx b/.vs/eSuite/FileContentIndex/ba823400-7c98-442e-8024-593cd4d5fef1.vsidx new file mode 100644 index 0000000..a6a158a Binary files /dev/null and b/.vs/eSuite/FileContentIndex/ba823400-7c98-442e-8024-593cd4d5fef1.vsidx differ diff --git a/.vs/eSuite/FileContentIndex/da446847-cad0-4e8c-b3bf-115014925172.vsidx b/.vs/eSuite/FileContentIndex/da446847-cad0-4e8c-b3bf-115014925172.vsidx new file mode 100644 index 0000000..8ad5d49 Binary files /dev/null and b/.vs/eSuite/FileContentIndex/da446847-cad0-4e8c-b3bf-115014925172.vsidx differ diff --git a/.vs/eSuite/FileContentIndex/f30ef7d9-2362-40a9-862d-91e66ea33bec.vsidx b/.vs/eSuite/FileContentIndex/f30ef7d9-2362-40a9-862d-91e66ea33bec.vsidx new file mode 100644 index 0000000..bb4395d Binary files /dev/null and b/.vs/eSuite/FileContentIndex/f30ef7d9-2362-40a9-862d-91e66ea33bec.vsidx differ diff --git a/.vs/eSuite/config/applicationhost.config b/.vs/eSuite/config/applicationhost.config new file mode 100644 index 0000000..0d88f0d --- /dev/null +++ b/.vs/eSuite/config/applicationhost.config @@ -0,0 +1,1016 @@ + + + + + + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.vs/eSuite/v17/.futdcache.v2 b/.vs/eSuite/v17/.futdcache.v2 new file mode 100644 index 0000000..c986608 Binary files /dev/null and b/.vs/eSuite/v17/.futdcache.v2 differ diff --git a/.vs/eSuite/v17/.suo b/.vs/eSuite/v17/.suo new file mode 100644 index 0000000..0194f98 Binary files /dev/null and b/.vs/eSuite/v17/.suo differ diff --git a/.vs/eSuite/v17/DocumentLayout.backup.json b/.vs/eSuite/v17/DocumentLayout.backup.json new file mode 100644 index 0000000..af2d292 --- /dev/null +++ b/.vs/eSuite/v17/DocumentLayout.backup.json @@ -0,0 +1,37 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\", + "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api\\esuite.api\\dependencyinjection\\coreregistrationmodule.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|solutionrelative:e-suite.api\\esuite.api\\dependencyinjection\\coreregistrationmodule.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + } + ], + "DocumentGroupContainers": [ + { + "Orientation": 1, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedHeight": 200, + "SelectedChildIndex": 0, + "Children": [ + { + "$type": "Document", + "DocumentIndex": 0, + "Title": "CoreRegistrationModule.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "RelativeDocumentMoniker": "e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "RelativeToolTip": "e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "ViewState": "AgIAABIAAAAAAAAAAAAAwCMAAABIAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2024-12-26T13:06:45.739Z", + "EditorCaption": "" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/.vs/eSuite/v17/DocumentLayout.json b/.vs/eSuite/v17/DocumentLayout.json new file mode 100644 index 0000000..af2d292 --- /dev/null +++ b/.vs/eSuite/v17/DocumentLayout.json @@ -0,0 +1,37 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\", + "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api\\esuite.api\\dependencyinjection\\coreregistrationmodule.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|solutionrelative:e-suite.api\\esuite.api\\dependencyinjection\\coreregistrationmodule.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + } + ], + "DocumentGroupContainers": [ + { + "Orientation": 1, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedHeight": 200, + "SelectedChildIndex": 0, + "Children": [ + { + "$type": "Document", + "DocumentIndex": 0, + "Title": "CoreRegistrationModule.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "RelativeDocumentMoniker": "e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "RelativeToolTip": "e-suite.API\\eSuite.API\\DependencyInjection\\CoreRegistrationModule.cs", + "ViewState": "AgIAABIAAAAAAAAAAAAAwCMAAABIAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2024-12-26T13:06:45.739Z", + "EditorCaption": "" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/.vs/eSuite/v18/.futdcache.v2 b/.vs/eSuite/v18/.futdcache.v2 new file mode 100644 index 0000000..b88aa70 Binary files /dev/null and b/.vs/eSuite/v18/.futdcache.v2 differ diff --git a/.vs/eSuite/v18/.suo b/.vs/eSuite/v18/.suo new file mode 100644 index 0000000..6dc85ad Binary files /dev/null and b/.vs/eSuite/v18/.suo differ diff --git a/.vs/eSuite/v18/DocumentLayout.backup.json b/.vs/eSuite/v18/DocumentLayout.backup.json new file mode 100644 index 0000000..e73205e --- /dev/null +++ b/.vs/eSuite/v18/DocumentLayout.backup.json @@ -0,0 +1,215 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\", + "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{974467C0-14E3-D020-066A-74EDE1567927}|e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api.common\\e-suite.api.common\\models\\readperformancereportsummary.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{974467C0-14E3-D020-066A-74EDE1567927}|e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj|solutionrelative:e-suite.api.common\\e-suite.api.common\\models\\readperformancereportsummary.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{974467C0-14E3-D020-066A-74EDE1567927}|e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api.common\\e-suite.api.common\\models\\readperformancereport.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{974467C0-14E3-D020-066A-74EDE1567927}|e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj|solutionrelative:e-suite.api.common\\e-suite.api.common\\models\\readperformancereport.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{7DC1F493-76A5-3740-E774-C8DAA51ED83A}|e-suite.API.Common\\e-suite.API.Common.UnitTests\\e-suite.API.Common.UnitTests.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api.common\\e-suite.api.common.unittests\\dtoautotester.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{7DC1F493-76A5-3740-E774-C8DAA51ED83A}|e-suite.API.Common\\e-suite.API.Common.UnitTests\\e-suite.API.Common.UnitTests.csproj|solutionrelative:e-suite.api.common\\e-suite.api.common.unittests\\dtoautotester.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api\\esuite.api\\swagger\\swaggerextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|solutionrelative:e-suite.api\\esuite.api\\swagger\\swaggerextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.api\\esuite.api\\swagger\\hasallowanonymousoperationsfilter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}|e-suite.API\\eSuite.API\\eSuite.API.csproj|solutionrelative:e-suite.api\\esuite.api\\swagger\\hasallowanonymousoperationsfilter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{CE69D868-8B81-B043-A340-E8F23683C0A2}|e-suite.Modules.SpecificationManager\\e-suite.Modules.SpecificationManager.UnitTests\\e-suite.Modules.SpecificationManager.UnitTests.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.modules.specificationmanager\\e-suite.modules.specificationmanager.unittests\\helpers\\fakeformrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{CE69D868-8B81-B043-A340-E8F23683C0A2}|e-suite.Modules.SpecificationManager\\e-suite.Modules.SpecificationManager.UnitTests\\e-suite.Modules.SpecificationManager.UnitTests.csproj|solutionrelative:e-suite.modules.specificationmanager\\e-suite.modules.specificationmanager.unittests\\helpers\\fakeformrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{B612A69B-3F3A-C33C-77F5-DE6A915E4E7D}|e-suite.Modules.OrganisationManager\\e-Suite.Modules.OrganisationManger.UnitTests\\e-suite.Modules.OrganisationsManager.UnitTests.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.modules.organisationmanager\\e-suite.modules.organisationmanger.unittests\\repository\\fakeorganisationmanagerrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{B612A69B-3F3A-C33C-77F5-DE6A915E4E7D}|e-suite.Modules.OrganisationManager\\e-Suite.Modules.OrganisationManger.UnitTests\\e-suite.Modules.OrganisationsManager.UnitTests.csproj|solutionrelative:e-suite.modules.organisationmanager\\e-suite.modules.organisationmanger.unittests\\repository\\fakeorganisationmanagerrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{5419EC24-755C-4D26-A6F1-90F478734EC3}|e-suite.MessageProcessor\\e-suite.MessageProcessor\\e-suite.MessageProcessor.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.messageprocessor\\e-suite.messageprocessor\\dependencyinjection\\coreregistrationmodule.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{5419EC24-755C-4D26-A6F1-90F478734EC3}|e-suite.MessageProcessor\\e-suite.MessageProcessor\\e-suite.MessageProcessor.csproj|solutionrelative:e-suite.messageprocessor\\e-suite.messageprocessor\\dependencyinjection\\coreregistrationmodule.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{F3A13EA7-AB5F-977E-3F71-82C5341119CD}|e-suite.Modules.FormsManager\\e_suite.Modules.Form.ManagerUnitTest\\e_suite.Modules.FormsManagerUnitTests.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.modules.formsmanager\\e_suite.modules.form.managerunittest\\fakeformsrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{F3A13EA7-AB5F-977E-3F71-82C5341119CD}|e-suite.Modules.FormsManager\\e_suite.Modules.Form.ManagerUnitTest\\e_suite.Modules.FormsManagerUnitTests.csproj|solutionrelative:e-suite.modules.formsmanager\\e_suite.modules.form.managerunittest\\fakeformsrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{73E50199-E462-B108-664A-1921E56D60A7}|e-suite.Modules.CustomFieldsManager\\e_suite.Modules.CusomFieldManagerUnitTest\\e_suite.Modules.CustomFieldManagerUnitTests.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.modules.customfieldsmanager\\e_suite.modules.cusomfieldmanagerunittest\\fakecustomfieldrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{73E50199-E462-B108-664A-1921E56D60A7}|e-suite.Modules.CustomFieldsManager\\e_suite.Modules.CusomFieldManagerUnitTest\\e_suite.Modules.CustomFieldManagerUnitTests.csproj|solutionrelative:e-suite.modules.customfieldsmanager\\e_suite.modules.cusomfieldmanagerunittest\\fakecustomfieldrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{A3A65D33-B1BA-4F89-4567-B45103987C1E}|e-suite.Service.EFlowSync\\e-suite.Service.EFlowSync.UnitTests\\e-suite.Service.EFlowSync.UnitTests.csproj|c:\\users\\me\\onedrive\\code\\sun\\e-suite\\e-suite.service.eflowsync\\e-suite.service.eflowsync.unittests\\fakerepositories\\fakeformsrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{A3A65D33-B1BA-4F89-4567-B45103987C1E}|e-suite.Service.EFlowSync\\e-suite.Service.EFlowSync.UnitTests\\e-suite.Service.EFlowSync.UnitTests.csproj|solutionrelative:e-suite.service.eflowsync\\e-suite.service.eflowsync.unittests\\fakerepositories\\fakeformsrepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + } + ], + "DocumentGroupContainers": [ + { + "Orientation": 1, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedHeight": 200, + "SelectedChildIndex": 0, + "Children": [ + { + "$type": "Document", + "DocumentIndex": 0, + "Title": "ReadPerformanceReportSummary.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReportSummary.cs", + "RelativeDocumentMoniker": "e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReportSummary.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReportSummary.cs", + "RelativeToolTip": "e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReportSummary.cs", + "ViewState": "AgIAAAQAAAAAAAAAAAAzwAgAAAAiAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:46:44.514Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 1, + "Title": "ReadPerformanceReport.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReport.cs", + "RelativeDocumentMoniker": "e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReport.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReport.cs", + "RelativeToolTip": "e-suite.API.Common\\e-suite.API.Common\\models\\ReadPerformanceReport.cs", + "ViewState": "AgIAAAUAAAAAAAAAAAAAAAoAAAAhAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:44:45.87Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 2, + "Title": "DtoAutoTester.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common.UnitTests\\DtoAutoTester.cs", + "RelativeDocumentMoniker": "e-suite.API.Common\\e-suite.API.Common.UnitTests\\DtoAutoTester.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common.UnitTests\\DtoAutoTester.cs", + "RelativeToolTip": "e-suite.API.Common\\e-suite.API.Common.UnitTests\\DtoAutoTester.cs", + "ViewState": "AgIAAAcAAAAAAAAAAAA8wBMAAAAJAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:44:17.876Z", + "EditorCaption": "" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{6da21f7a-58db-45ce-8a78-22e8ff00cb95}" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{4e0252e6-905c-4466-b94e-c0b946fda83c}" + }, + { + "$type": "Document", + "DocumentIndex": 3, + "Title": "SwaggerExtension.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\Swagger\\SwaggerExtension.cs", + "RelativeDocumentMoniker": "e-suite.API\\eSuite.API\\Swagger\\SwaggerExtension.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\Swagger\\SwaggerExtension.cs", + "RelativeToolTip": "e-suite.API\\eSuite.API\\Swagger\\SwaggerExtension.cs", + "ViewState": "AgIAACUAAAAAAAAAAAAQwAEAAAAXAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:39:00.498Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 4, + "Title": "HasAllowAnonymousOperationsFilter.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\Swagger\\HasAllowAnonymousOperationsFilter.cs", + "RelativeDocumentMoniker": "e-suite.API\\eSuite.API\\Swagger\\HasAllowAnonymousOperationsFilter.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API\\eSuite.API\\Swagger\\HasAllowAnonymousOperationsFilter.cs", + "RelativeToolTip": "e-suite.API\\eSuite.API\\Swagger\\HasAllowAnonymousOperationsFilter.cs", + "ViewState": "AgIAAAkAAAAAAAAAAAA7wBwAAAAJAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:38:02.181Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 5, + "Title": "FakeFormRepository.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.SpecificationManager\\e-suite.Modules.SpecificationManager.UnitTests\\Helpers\\FakeFormRepository.cs", + "RelativeDocumentMoniker": "e-suite.Modules.SpecificationManager\\e-suite.Modules.SpecificationManager.UnitTests\\Helpers\\FakeFormRepository.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.SpecificationManager\\e-suite.Modules.SpecificationManager.UnitTests\\Helpers\\FakeFormRepository.cs", + "RelativeToolTip": "e-suite.Modules.SpecificationManager\\e-suite.Modules.SpecificationManager.UnitTests\\Helpers\\FakeFormRepository.cs", + "ViewState": "AgIAAGEAAAAAAAAAAAAqwGwAAAAsAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:37:50.818Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 6, + "Title": "FakeOrganisationManagerRepository.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.OrganisationManager\\e-Suite.Modules.OrganisationManger.UnitTests\\Repository\\FakeOrganisationManagerRepository.cs", + "RelativeDocumentMoniker": "e-suite.Modules.OrganisationManager\\e-Suite.Modules.OrganisationManger.UnitTests\\Repository\\FakeOrganisationManagerRepository.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.OrganisationManager\\e-Suite.Modules.OrganisationManger.UnitTests\\Repository\\FakeOrganisationManagerRepository.cs", + "RelativeToolTip": "e-suite.Modules.OrganisationManager\\e-Suite.Modules.OrganisationManger.UnitTests\\Repository\\FakeOrganisationManagerRepository.cs", + "ViewState": "AgIAAA8AAAAAAAAAAAASwBgAAABFAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:37:42.769Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 7, + "Title": "CoreRegistrationModule.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.MessageProcessor\\e-suite.MessageProcessor\\DependencyInjection\\CoreRegistrationModule.cs", + "RelativeDocumentMoniker": "e-suite.MessageProcessor\\e-suite.MessageProcessor\\DependencyInjection\\CoreRegistrationModule.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.MessageProcessor\\e-suite.MessageProcessor\\DependencyInjection\\CoreRegistrationModule.cs", + "RelativeToolTip": "e-suite.MessageProcessor\\e-suite.MessageProcessor\\DependencyInjection\\CoreRegistrationModule.cs", + "ViewState": "AgIAACkAAAAAAAAAAAASwDIAAAATAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:36:59.391Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 8, + "Title": "FakeFormsRepository.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.FormsManager\\e_suite.Modules.Form.ManagerUnitTest\\FakeFormsRepository.cs", + "RelativeDocumentMoniker": "e-suite.Modules.FormsManager\\e_suite.Modules.Form.ManagerUnitTest\\FakeFormsRepository.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.FormsManager\\e_suite.Modules.Form.ManagerUnitTest\\FakeFormsRepository.cs", + "RelativeToolTip": "e-suite.Modules.FormsManager\\e_suite.Modules.Form.ManagerUnitTest\\FakeFormsRepository.cs", + "ViewState": "AgIAABMAAAAAAAAAAAASwBwAAABVAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:36:51.024Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 9, + "Title": "FakeCustomFieldRepository.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.CustomFieldsManager\\e_suite.Modules.CusomFieldManagerUnitTest\\FakeCustomFieldRepository.cs", + "RelativeDocumentMoniker": "e-suite.Modules.CustomFieldsManager\\e_suite.Modules.CusomFieldManagerUnitTest\\FakeCustomFieldRepository.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.CustomFieldsManager\\e_suite.Modules.CusomFieldManagerUnitTest\\FakeCustomFieldRepository.cs", + "RelativeToolTip": "e-suite.Modules.CustomFieldsManager\\e_suite.Modules.CusomFieldManagerUnitTest\\FakeCustomFieldRepository.cs", + "ViewState": "AgIAAA0AAAAAAAAAAIAzwBYAAAA8AAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:36:43.076Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 10, + "Title": "FakeFormsRepository.cs", + "DocumentMoniker": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Service.EFlowSync\\e-suite.Service.EFlowSync.UnitTests\\FakeRepositories\\FakeFormsRepository.cs", + "RelativeDocumentMoniker": "e-suite.Service.EFlowSync\\e-suite.Service.EFlowSync.UnitTests\\FakeRepositories\\FakeFormsRepository.cs", + "ToolTip": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Service.EFlowSync\\e-suite.Service.EFlowSync.UnitTests\\FakeRepositories\\FakeFormsRepository.cs", + "RelativeToolTip": "e-suite.Service.EFlowSync\\e-suite.Service.EFlowSync.UnitTests\\FakeRepositories\\FakeFormsRepository.cs", + "ViewState": "AgIAABMAAAAAAAAAAIAxwBsAAABUAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-20T14:36:09.899Z", + "EditorCaption": "" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/.vs/eSuite/v18/DocumentLayout.json b/.vs/eSuite/v18/DocumentLayout.json new file mode 100644 index 0000000..ff6cba3 --- /dev/null +++ b/.vs/eSuite/v18/DocumentLayout.json @@ -0,0 +1,23 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\", + "Documents": [], + "DocumentGroupContainers": [ + { + "Orientation": 1, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedHeight": 200, + "SelectedChildIndex": -1, + "Children": [ + { + "$type": "Bookmark", + "Name": "ST:0:0:{4e0252e6-905c-4466-b94e-c0b946fda83c}" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/.vs/eSuite/v18/fileList.bin b/.vs/eSuite/v18/fileList.bin new file mode 100644 index 0000000..d897598 Binary files /dev/null and b/.vs/eSuite/v18/fileList.bin differ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7a9dfa0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/Sigma server connects for Colin.txt b/Sigma server connects for Colin.txt new file mode 100644 index 0000000..1aee988 --- /dev/null +++ b/Sigma server connects for Colin.txt @@ -0,0 +1,89 @@ + +Sigma Airlock + +Database: + +airlock + +Internal IP: +172.27.18.45 + + +External IP: +87.224.57.13 + + +Username: +e-suite.18.45 + +Password: + +s2f$yuSbVAd;&rXNUeP'@Z + +****************************************************** + + +Sigma Printer checklist + +Database: + +external crom + +Internal IP: +172.27.17.228 + +External IP: + +87.224.57.32 + +Username: +e-suite.service.228 + +Password: + +Y2:y`4Q#Su+cm/LK!Vv~8< + +****************************************************** + + +Sigma web live + +Database: +si6ma + +Internal IP: +172.27.18.22 + +External IP: +87.224.57.12 + + +Username: +e-suite-18-22 + +Password: +J]v6mjL#Cf3^E;?4as5cQ + + +****************************************************** + + +Webstore + +Database: +ftpu + +Internal IP: +172.27.18.63 + + +External IP: +87.224.57.9 + + +Username: +e-suite.18.63 + +Password: + +f9X{,W%3E8$`VR"Y>=vLqM \ No newline at end of file diff --git a/e-suite.API.Common/.gitattributes b/e-suite.API.Common/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.API.Common/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.API.Common/.gitignore b/e-suite.API.Common/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.API.Common/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.API.Common/.runsettings b/e-suite.API.Common/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.API.Common/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.API.Common/README.md b/e-suite.API.Common/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.API.Common/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.API.Common/azure-pipelines.yml b/e-suite.API.Common/azure-pipelines.yml new file mode 100644 index 0000000..bd7d20e --- /dev/null +++ b/e-suite.API.Common/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.API.Common/e-suite.API.Common.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common.UnitTests/CustomFieldValueExtensionsUnitTests.cs b/e-suite.API.Common/e-suite.API.Common.UnitTests/CustomFieldValueExtensionsUnitTests.cs new file mode 100644 index 0000000..6ac299f --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.UnitTests/CustomFieldValueExtensionsUnitTests.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.API.Common.UnitTests; + +[TestFixture] +public class CustomFieldValueExtensionsUnitTests +{ + [Test] + public void test() + { + //Arrange + var values = new List(); + values.Add(new CustomFieldValues + { + Id = new GeneralIdRef + { + Id = 666, + Guid = new Guid("c8564cb3-9d42-4a56-8b0d-df1792cd6c4a") + }, + Values = new List + { + new() + { + Value = "Hello", + DisplayValue = "Hello Display" + } + } + }); + + //Act + var results = values.ToCustomFieldsValues(); + + //Assert + Assert.That(results.Count, Is.EqualTo(1)); + Assert.That(results[0].Id.Id, Is.EqualTo(666)); + Assert.That(results[0].Id.Guid, Is.EqualTo(new Guid("c8564cb3-9d42-4a56-8b0d-df1792cd6c4a"))); + Assert.That(results[0].Values.Count, Is.EqualTo(1)); + Assert.That(results[0].Values[0].Value, Is.EqualTo("Hello")); + Assert.That(results[0].Values[0].DisplayValue, Is.EqualTo("Hello Display")); + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common.UnitTests/DtoAutoTester.cs b/e-suite.API.Common/e-suite.API.Common.UnitTests/DtoAutoTester.cs new file mode 100644 index 0000000..d0ff40d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.UnitTests/DtoAutoTester.cs @@ -0,0 +1,102 @@ +using System.Reflection; +using e_suite.API.Common.models; +using NUnit.Framework; + +namespace e_suite.API.Common.UnitTests; + +[TestFixture] +public class DtoAutoTester +{ + [Test] + public void RunTests() + { + var modelsList = new List(); + + var assembly = Assembly.GetAssembly(typeof(AddRoleSecurityAccess)); + + var allTypes = assembly!.GetTypes().Where( x => x.Namespace == "e_suite.API.Common.models"); + + foreach (var type in allTypes) + { + RunTestsOnClass(type); + } + } + + private static void RunTestsOnClass(Type type) + { + if (type.IsAbstract) + return; //Nothing to test here, as abstract classes do not get created. + + if (type.DeclaringType != null) + return; //types that have a declaring type are doing something funky, and I don't want to test them directly. + + //Create an instance of the object to play with. + var instance = Activator.CreateInstance(type); + + var allProperties = type.GetProperties(); + foreach (var property in allProperties) + { + if (property.CanWrite) + TestCanWrite(property, instance); + + if (property.CanRead) + TestCanRead(property, instance); + } + } + + private static void TestCanRead(PropertyInfo property, object? instance) + { + try + { + var result = property.GetValue(instance); + } + catch(Exception ex) + { + Assert.Fail(ex.Message); + } + } + + private static void TestCanWrite(PropertyInfo property, object? instance) + { + var propertyType = property.PropertyType; + + if (propertyType.IsInterface) + { + try + { + var actualPropertyType = GetTypeForInterface(propertyType); + + var writeValue = Activator.CreateInstance(actualPropertyType!); + property.SetValue(instance, writeValue, null); + } + catch (Exception ex) + { + Assert.Fail(ex.ToString()); + } + } + else if (propertyType != typeof(string)) + { + try + { + var writeValue = Activator.CreateInstance(property.PropertyType); + property.SetValue(instance, writeValue, null); + } + catch (Exception ex) + { + Assert.Fail(ex.ToString()); + } + } + } + + private static Type? GetTypeForInterface(Type propertyType) + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + + var alltypes = assemblies + .SelectMany(s => s.GetTypes()).ToList(); + + var actualPropertyType = alltypes + .FirstOrDefault(p => p.GetInterfaces().Any(x => x == propertyType)); + return actualPropertyType; + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common.UnitTests/ExceptionUnitTests.cs b/e-suite.API.Common/e-suite.API.Common.UnitTests/ExceptionUnitTests.cs new file mode 100644 index 0000000..5b48462 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.UnitTests/ExceptionUnitTests.cs @@ -0,0 +1,22 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.UnitTests.helper; +using NUnit.Framework; + +namespace e_suite.API.Common.UnitTests; + +[TestFixture] +public class ExceptionUnitTests +{ + [TestCase(typeof(ExistsException))] + [TestCase(typeof(InvalidEmailException))] + [TestCase(typeof(InvalidReferenceObjectId))] + [TestCase(typeof(MaximumRangeException))] + [TestCase(typeof(MinimumRangeException))] + [TestCase(typeof(NotFoundException))] + [TestCase(typeof(TokenInvalidException))] + [TestCase(typeof(WeakPasswordException))] + public void ExistsException_PerformExcpetionTests(Type testcase) + { + ExceptionTester.PerformTestSuite(testcase); + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common.UnitTests/ValidateUnitTests.cs b/e-suite.API.Common/e-suite.API.Common.UnitTests/ValidateUnitTests.cs new file mode 100644 index 0000000..c5b7f8e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.UnitTests/ValidateUnitTests.cs @@ -0,0 +1,164 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using NUnit.Framework; + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class ValidateUnitTests +{ + [Test] + public void Validate_MissingNumericPlaceholder_FailValidation() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 1, + Name = "Sequence name", + Pattern = "{DD}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + var context = new ValidationContext(sequence); + + // Act + var results = sequence.Validate(context).ToList(); + + // Assert + Assert.That(results.Count, Is.EqualTo(1)); + Assert.That(results[0].MemberNames.Count(), Is.EqualTo(1)); + Assert.That(results[0].MemberNames.ToList()[0], Is.EqualTo(nameof(Sequence.Pattern))); + Assert.That(results[0].ErrorMessage, Is.EqualTo("At minimum all patterns must contain one numeric value (i.e. [0])")); + } + + [Test] + public void Validate_MissingYearPlaceholder_FailValidation() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 1, + Name = "Sequence name", + Pattern = "Order-[000]", + RolloverType = Rollover.Year, + Seed = 1 + }; + + var context = new ValidationContext(sequence); + + // Act + var results = sequence.Validate(context).ToList(); + + // Asserts + Assert.That(results.Count, Is.EqualTo(1)); + Assert.That(results[0].MemberNames.Count(), Is.EqualTo(1)); + Assert.That(results[0].MemberNames.ToList()[0], Is.EqualTo(nameof(Sequence.Pattern))); + Assert.That(results[0].ErrorMessage, Is.EqualTo("When the rollover type is set to 'Annual', then the pattern must include either a {YY} or {YYYY} placeholder")); + } + + [Test] + public void Validate_MissingMonthPlaceholder_FailValidation() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 1, + Name = "Sequence name", + Pattern = "Order-[000]", + RolloverType = Rollover.Month, + Seed = 1 + }; + + var context = new ValidationContext(sequence); + + // Act + var results = sequence.Validate(context).ToList(); + + // Asserts + Assert.That(results.Count, Is.EqualTo(1)); + Assert.That(results[0].MemberNames.Count(), Is.EqualTo(1)); + Assert.That(results[0].MemberNames.ToList()[0], Is.EqualTo(nameof(Sequence.Pattern))); + Assert.That(results[0].ErrorMessage, Is.EqualTo("When the rollover type is set to 'Monthly', then the pattern must include either a {MM} placeholder")); + } + + [Test] + public void Validate_MissingDayPlaceholder_FailValidation() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 1, + Name = "Sequence name", + Pattern = "Order-[000]", + RolloverType = Rollover.Day, + Seed = 1 + }; + + var context = new ValidationContext(sequence); + + // Act + var results = sequence.Validate(context).ToList(); + + // Asserts + Assert.That(results.Count, Is.EqualTo(1)); + Assert.That(results[0].MemberNames.Count(), Is.EqualTo(1)); + Assert.That(results[0].MemberNames.ToList()[0], Is.EqualTo(nameof(Sequence.Pattern))); + Assert.That(results[0].ErrorMessage, Is.EqualTo("When the rollover type is set to 'Daily', then the pattern must include either a {DD} placeholder")); + } + + [Test] + public void Validate_Validation_Pass() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + var context = new ValidationContext(sequence); + + // Act + var results = sequence.Validate(context).ToList(); + + // Assert + Assert.That(results.Count, Is.EqualTo(0)); + } + + [Test] + public void Validate_Increment0_Fails() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 0, + Name = "Sequence name", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + var context = new ValidationContext(sequence); + + // Act + var results = sequence.Validate(context).ToList(); + + // Assert + Assert.That(results.Count, Is.EqualTo(1)); + Assert.That(results[0].MemberNames.Count(), Is.EqualTo(1)); + Assert.That(results[0].MemberNames.ToList()[0], Is.EqualTo(nameof(Sequence.Increment))); + Assert.That(results[0].ErrorMessage, Is.EqualTo("Increment can not be 0")); + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common.UnitTests/e-suite.API.Common.UnitTests.csproj b/e-suite.API.Common/e-suite.API.Common.UnitTests/e-suite.API.Common.UnitTests.csproj new file mode 100644 index 0000000..376715e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.UnitTests/e-suite.API.Common.UnitTests.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + e_suite.API.Common.UnitTests + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.API.Common/e-suite.API.Common.UnitTests/helper/ExceptionTester.cs b/e-suite.API.Common/e-suite.API.Common.UnitTests/helper/ExceptionTester.cs new file mode 100644 index 0000000..ebfc69a --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.UnitTests/helper/ExceptionTester.cs @@ -0,0 +1,57 @@ +using NUnit.Framework; + +namespace e_suite.API.Common.UnitTests.helper; + +public static class ExceptionTester +{ + public static void PerformTestSuite(Type exceptionUnderTest) + { + Assert.That(exceptionUnderTest, Is.Not.Null); + Assert.That(InheritsFrom(exceptionUnderTest), Is.True); + Assert.That(CreateInstanceWithNoMessage(exceptionUnderTest), Is.True); + Assert.That(CreateInstanceWithMessage(exceptionUnderTest), Is.True); + Assert.That(CreateInstanceWithMessageAndInnerException(exceptionUnderTest), Is.True); + } + + private static bool CreateInstanceWithMessageAndInnerException(Type exceptionUnderTest) + { + var innerException = new Exception("InnerException"); + + var newInstance = (Exception)Activator.CreateInstance(exceptionUnderTest, "Test", innerException)!; + + Assert.That(newInstance, Is.Not.Null); + Assert.That(newInstance?.InnerException, Is.EqualTo(innerException)); + + return newInstance?.GetType() == exceptionUnderTest; + } + + private static bool CreateInstanceWithMessage(Type exceptionUnderTest) + { + var newInstance = Activator.CreateInstance(exceptionUnderTest, "Test"); + Assert.That(newInstance, Is.Not.Null); + return newInstance?.GetType() == exceptionUnderTest; + } + + private static bool CreateInstanceWithNoMessage(Type exceptionUnderTest) + { + var newInstance = Activator.CreateInstance(exceptionUnderTest); + Assert.That(newInstance, Is.Not.Null); + return newInstance?.GetType() == exceptionUnderTest; + } + + private static bool InheritsFrom(Type exceptionUnderTest) + { + var typeUnderTest = exceptionUnderTest; + + while (typeUnderTest != null) + { + if (typeUnderTest == typeof(T)) + { + return true; + } + typeUnderTest = typeUnderTest.BaseType; + } + + return false; + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common.sln b/e-suite.API.Common/e-suite.API.Common.sln new file mode 100644 index 0000000..2082796 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.API.Common", "e-suite.API.Common\e-suite.API.Common.csproj", "{B83BC836-F72F-4109-ABEF-6DBFB0D32CF3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{E3CF6121-8D87-4C4B-A3EE-73AE78F92DF4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{D4A0A029-718D-436F-AECE-F04CCD4FDD65}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.API.Common.UnitTests", "e-suite.API.Common.UnitTests\e-suite.API.Common.UnitTests.csproj", "{4D647593-4BEA-4ACB-A886-82491D703E52}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B83BC836-F72F-4109-ABEF-6DBFB0D32CF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B83BC836-F72F-4109-ABEF-6DBFB0D32CF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B83BC836-F72F-4109-ABEF-6DBFB0D32CF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B83BC836-F72F-4109-ABEF-6DBFB0D32CF3}.Release|Any CPU.Build.0 = Release|Any CPU + {4D647593-4BEA-4ACB-A886-82491D703E52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D647593-4BEA-4ACB-A886-82491D703E52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D647593-4BEA-4ACB-A886-82491D703E52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D647593-4BEA-4ACB-A886-82491D703E52}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D4A0A029-718D-436F-AECE-F04CCD4FDD65} = {E3CF6121-8D87-4C4B-A3EE-73AE78F92DF4} + {4D647593-4BEA-4ACB-A886-82491D703E52} = {D4A0A029-718D-436F-AECE-F04CCD4FDD65} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {63B8E197-C2CC-44D5-8FE3-4DB963DB9D2B} + EndGlobalSection +EndGlobal diff --git a/e-suite.API.Common/e-suite.API.Common/IAuditLog.cs b/e-suite.API.Common/e-suite.API.Common/IAuditLog.cs new file mode 100644 index 0000000..2283e4d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IAuditLog.cs @@ -0,0 +1,10 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; + +namespace e_suite.API.Common; + +public interface IAuditLog +{ + Task> GetAuditLogEntries(Paging paging, string? logEntry, bool primaryOnly, + CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IBlockedIPsManager.cs b/e-suite.API.Common/e-suite.API.Common/IBlockedIPsManager.cs new file mode 100644 index 0000000..219e6be --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IBlockedIPsManager.cs @@ -0,0 +1,12 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; + +namespace e_suite.API.Common; + +public interface IBlockedIPsManager +{ + Task> GetBlockedIPs(Paging paging, CancellationToken cancellationToken); + + Task UnblockIPAddress(AuditUserDetails auditUserDetails, string ipaddress, CancellationToken cancellationToken); +} diff --git a/e-suite.API.Common/e-suite.API.Common/IContactsManager.cs b/e-suite.API.Common/e-suite.API.Common/IContactsManager.cs new file mode 100644 index 0000000..3de4368 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IContactsManager.cs @@ -0,0 +1,12 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IContactsManager +{ + Task CreateContact(AuditUserDetails auditUserDetails, CreateContact createContactDto, CancellationToken cancellationToken); + Task EditContact(AuditUserDetails auditUserDetails, EditContact editContactDto, CancellationToken cancellationToken); + Task GetContact(GeneralIdRef generalIdRef, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ICustomFieldHelper.cs b/e-suite.API.Common/e-suite.API.Common/ICustomFieldHelper.cs new file mode 100644 index 0000000..9338e49 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ICustomFieldHelper.cs @@ -0,0 +1,18 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface ICustomFieldHelper +{ + Task TranslateToCustomFieldDefinitionAsync(CustomField customField, CancellationToken cancellationToken); + Task GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + Task GetGlossaryByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + Task GetDomainByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + Task> CustomFieldValuesList(IEnumerable enumerableCustomFieldValues, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ICustomFieldManager.cs b/e-suite.API.Common/e-suite.API.Common/ICustomFieldManager.cs new file mode 100644 index 0000000..df024d9 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ICustomFieldManager.cs @@ -0,0 +1,19 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface ICustomFieldManager +{ + Task> GetFieldsAsync(Paging paging, CancellationToken cancellationToken); + Task CreateFieldAsync(AuditUserDetails auditUserDetails, CreateCustomField custimField, CancellationToken cancellationToken); + Task EditFieldAsync(AuditUserDetails auditUserDetails, EditCustomFields custimField, CancellationToken cancellationToken); + + Task GetFieldAsync(IGeneralIdRef id, CancellationToken cancellationToken); + + Task GetFieldAsync(string name, CancellationToken cancellationToken); + + Task DeleteFieldAsync(AuditUserDetails auditUserDetails, IGeneralIdRef id, CancellationToken cancellationToken); +} diff --git a/e-suite.API.Common/e-suite.API.Common/ICustomFieldValidator.cs b/e-suite.API.Common/e-suite.API.Common/ICustomFieldValidator.cs new file mode 100644 index 0000000..0e8ab81 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ICustomFieldValidator.cs @@ -0,0 +1,11 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.CustomFields; + +namespace e_suite.API.Common; + +public interface ICustomFieldValidator +{ + Task> ValidateFields(AuditUserDetails auditUserDetails, IEnumerable customFieldValues, + IReadOnlyCollection customFields, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IDomainManager.cs b/e-suite.API.Common/e-suite.API.Common/IDomainManager.cs new file mode 100644 index 0000000..ae9bdf4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IDomainManager.cs @@ -0,0 +1,18 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IDomainManager +{ + public Task> GetDomainsAsync(Paging paging, CancellationToken cancellationToken); + public Task GetDomainAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + + public Task CreateDomainAsync(AuditUserDetails auditUserDetails, CreateDomain createDomain, CancellationToken cancellationToken); + + public Task EditDomainAsync(AuditUserDetails auditUserDetails, EditDomain editDomain, CancellationToken cancellationToken); + + public Task DeleteDomainAsync(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IEFlowSync.cs b/e-suite.API.Common/e-suite.API.Common/IEFlowSync.cs new file mode 100644 index 0000000..1b9aea1 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IEFlowSync.cs @@ -0,0 +1,8 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IEFlowSync +{ + Task SyncEFlowPrinterCategories(List fullMessageDomains); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IExceptionLogManager.cs b/e-suite.API.Common/e-suite.API.Common/IExceptionLogManager.cs new file mode 100644 index 0000000..517e1c5 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IExceptionLogManager.cs @@ -0,0 +1,11 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; + +namespace e_suite.API.Common; + +public interface IExceptionLogManager +{ + Task LogException(Exception ex, string application, string supportingArgs, CancellationToken cancellationToken); + + Task> GetExceptionLogs(Paging paging, CancellationToken cancellationToken); +} diff --git a/e-suite.API.Common/e-suite.API.Common/IFormsManager.cs b/e-suite.API.Common/e-suite.API.Common/IFormsManager.cs new file mode 100644 index 0000000..23e2a60 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IFormsManager.cs @@ -0,0 +1,27 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IFormsManager +{ + Task CreateFormTemplateAsync(AuditUserDetails auditUserDetails, CreateFormTemplate createFormTemplate, CancellationToken cancellationToken); + + Task EditFormTemplateAsync(AuditUserDetails auditUserDetails, EditFormTemplate editFormTemplate, CancellationToken cancellationToken); + + Task GetFormTemplateAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + + Task> GetFormTemplatesAsync(Paging paging, CancellationToken cancellationToken); + + Task DeleteFormTemplateAsync(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + + Task CreateFormInstanceAsync(AuditUserDetails auditUserDetails, CreateFormInstance createFormInstance, CancellationToken cancellationToken); + Task CreateFormInstancesAsync(AuditUserDetails auditUserDetails, IEnumerable createFormInstance, CancellationToken cancellationToken); + Task GetFormInstanceAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task> GetFormInstanceAsync(IEnumerable generalIdRefs, CancellationToken cancellationToken); + + Task EditFormInstanceAsync(AuditUserDetails auditUserDetails, EditFormInstance editFormInstance, CancellationToken cancellationToken); + Task EditFormInstanceAsync(AuditUserDetails auditUserDetails, IEnumerable editFormInstances, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IGlossariesManager.cs b/e-suite.API.Common/e-suite.API.Common/IGlossariesManager.cs new file mode 100644 index 0000000..b10f404 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IGlossariesManager.cs @@ -0,0 +1,14 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IGlossariesManager +{ + Task AddGlossaryItem(AuditUserDetails auditUserDetails, NewGlossaryItem glossaryItem, CancellationToken cancellationToken); + Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable glossaryItems, CancellationToken cancellationToken); + Task DeleteGlossaryItem(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetGlossaryItem(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task UpdateGlossaryItem(AuditUserDetails auditUserDetails, EditGlossaryItem editGlossaryItem, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IMailTemplateManager.cs b/e-suite.API.Common/e-suite.API.Common/IMailTemplateManager.cs new file mode 100644 index 0000000..c238e90 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IMailTemplateManager.cs @@ -0,0 +1,14 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IMailTemplateManager +{ + Task> GetMailTemplateTypes(Paging paging, CancellationToken cancellationToken); + Task GetMailTemplate( IGeneralIdRef domain, MailType mailType, CancellationToken cancellationToken); + Task PostMailTemplate(PostMailTemplate mailTemplate, AuditUserDetails auditUserDetails, CancellationToken cancellationToken ); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IOrganisationsManager.cs b/e-suite.API.Common/e-suite.API.Common/IOrganisationsManager.cs new file mode 100644 index 0000000..0a8d28f --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IOrganisationsManager.cs @@ -0,0 +1,17 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IOrganisationsManager +{ + Task> GetOrganisationList(Paging paging, CancellationToken cancellationToken); + Task AddOrganisation(AuditUserDetails auditUserDetails, CreateOrganisation addOrganisationDto, bool triggerEFlowSync, CancellationToken cancellationToken); + Task DeleteOrganisation(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, bool triggerEFlowSync, CancellationToken cancellationToken); + Task EditOrganisation(AuditUserDetails auditUserDetails, EditOrganisation editOrganisationDto, bool triggerEFlowSync, CancellationToken cancellationToken); + Task GetOrganisation(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IPerformanceMaintenance.cs b/e-suite.API.Common/e-suite.API.Common/IPerformanceMaintenance.cs new file mode 100644 index 0000000..779a2c5 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IPerformanceMaintenance.cs @@ -0,0 +1,6 @@ +namespace e_suite.API.Common; + +public interface IPerformanceMaintenance +{ + Task ClearOldPerformanceData(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IPerformanceManager.cs b/e-suite.API.Common/e-suite.API.Common/IPerformanceManager.cs new file mode 100644 index 0000000..28833e3 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IPerformanceManager.cs @@ -0,0 +1,5 @@ +namespace e_suite.API.Common; + +public interface IPerformanceManager +{ +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IRoleManager.cs b/e-suite.API.Common/e-suite.API.Common/IRoleManager.cs new file mode 100644 index 0000000..191f349 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IRoleManager.cs @@ -0,0 +1,29 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; + +namespace e_suite.API.Common; + +public interface IRoleManager +{ + Task> GetRoles(Paging paging, IGeneralIdRef domain, CancellationToken cancellationToken); + + Task GetRole(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + + Task CreateRole(AuditUserDetails auditUserDetails, CreateRole sequence, CancellationToken cancellationToken); + Task DeleteRole(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task EditRole(AuditUserDetails auditUserDetails, EditRole editSequence, CancellationToken cancellationToken); + Task> GetRoleUsers(Paging paging, GeneralIdRef roleId, CancellationToken cancellationToken); + Task AddRoleUser(AuditUserDetails auditUserDetails, UserRoleIds userRole, CancellationToken cancellationToken); + Task DeleteRoleUser(AuditUserDetails auditUserDetails, UserRoleIds userRole, CancellationToken cancellationToken); + Task>GetAccessList(Paging paging, CancellationToken cancellationToken); + Task> GetRoleAccess(Paging paging, CancellationToken cancellationToken); + Task AddRoleSecurityAccess(AuditUserDetails auditUserDetails, AddRoleSecurityAccess accessToAdd, CancellationToken cancellationToken); + Task DeleteRoleSecurityAccess(AuditUserDetails auditUserDetails, DeleteRoleSecurityAccess accessToRemove, CancellationToken cancellationToken); + Task HasAnyAccess(long? userId, SecurityAccess accessKey); + Task CheckHasDomainAccess(long userId, IGeneralIdRef? specificDomain, SecurityAccess accessKey, CancellationToken cancellationToken); + IEnumerable GetMyUserAccess(User user); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ISequenceManager.cs b/e-suite.API.Common/e-suite.API.Common/ISequenceManager.cs new file mode 100644 index 0000000..cf236c0 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ISequenceManager.cs @@ -0,0 +1,17 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface ISequenceManager +{ + Task GetSequence(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task CreateSequence(AuditUserDetails auditUserDetails, NewSequence sequence, CancellationToken cancellationToken); + Task DeleteSequence(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task EditSequence(AuditUserDetails auditUserDetails, Sequence editSequence, CancellationToken cancellationToken); + Task> GetSequences(Paging paging, CancellationToken cancellationToken); + Task> NextValue(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task> NextValue(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, int number, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ISigmaImporter.cs b/e-suite.API.Common/e-suite.API.Common/ISigmaImporter.cs new file mode 100644 index 0000000..745d0e7 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ISigmaImporter.cs @@ -0,0 +1,8 @@ +namespace e_suite.API.Common; + +public interface ISigmaImporter +{ + Task ImportGMGProfiles(); + + Task ImportPrintSpecifications(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ISiteManager.cs b/e-suite.API.Common/e-suite.API.Common/ISiteManager.cs new file mode 100644 index 0000000..1e95ced --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ISiteManager.cs @@ -0,0 +1,20 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface ISiteManager +{ + Task> GetSites(Paging paging, CancellationToken cancellationToken); + + Task GetSite(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetSiteByName(IGeneralIdRef organisationGeneralIdRef, string siteName, CancellationToken cancellationToken); + Task GetSiteBySigmaId(long sigmaId, CancellationToken cancellationToken); + + Task CreateSite(AuditUserDetails auditUserDetails, CreateSite site, bool triggerEFlowSync, CancellationToken cancellationToken); + Task CreateSites(AuditUserDetails auditUserDetails, IEnumerable sites, bool triggerEFlowSync, CancellationToken cancellationToken); + Task EditSite(AuditUserDetails auditUserDetails, EditSite site, bool triggerEFlowSync, CancellationToken cancellationToken); + Task DeleteSite(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, bool triggerEFlowSync, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ISpecificationManager.cs b/e-suite.API.Common/e-suite.API.Common/ISpecificationManager.cs new file mode 100644 index 0000000..1a5913c --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ISpecificationManager.cs @@ -0,0 +1,18 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface ISpecificationManager +{ + Task GetTemplateForPrintSpec(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task> GetSpecifications(Paging paging, CancellationToken cancellationToken); + Task GetSpecification(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task CreateSpecification(AuditUserDetails auditUserDetails, CreateSpecification create, bool triggerEFlowSync, CancellationToken cancellationToken); + Task CreateSpecification(AuditUserDetails auditUserDetails, IEnumerable create, bool triggerEFlowSync, CancellationToken cancellationToken); + Task DeleteSpecification(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, bool triggerEFlowSync, CancellationToken cancellationToken); + Task EditSpecification(AuditUserDetails auditUserDetails, EditSpecification edit, bool triggerEFlowSync, CancellationToken cancellationToken); + Task EditSpecification(AuditUserDetails auditUserDetails, IEnumerable items, bool triggerEFlowSync, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/ISsoManager.cs b/e-suite.API.Common/e-suite.API.Common/ISsoManager.cs new file mode 100644 index 0000000..18b52fb --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/ISsoManager.cs @@ -0,0 +1,15 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface ISsoManager +{ + Task> GetSsoProvidersAsync(Paging paging, CancellationToken cancellationToken); + Task GetSsoProviderAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task AddSsoProviderAsync(AuditUserDetails auditUserDetails, CreateSsoProvider ssoProvider, CancellationToken cancellationToken); + Task EditSsoProviderAsync(AuditUserDetails auditUserDetails, EditSsoProvider ssoProvider, CancellationToken cancellationToken); + Task RemoveSsoProviderAsync( AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IUserManager.cs b/e-suite.API.Common/e-suite.API.Common/IUserManager.cs new file mode 100644 index 0000000..e5a2b2d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IUserManager.cs @@ -0,0 +1,37 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common; + +public interface IUserManager +{ + Task Login(Login login, CancellationToken cancellationToken = default!); + Task LoginSso(long ssoId, string ssoUserId, CancellationToken cancellationToken = default!); + Task ForgotPassword(string email, CancellationToken cancellationToken = default!); + Task CreateUser(AuditUserDetails auditUserDetails, UserRegistration userRegistration, CancellationToken cancellationToken = default!); + Task RefreshToken(string email, CancellationToken cancellationToken = default!); + Task RefreshToken(IGeneralIdRef id, CancellationToken cancellationToken = default!); + Task CompleteEmailAction(EmailActionToken token, CancellationToken cancellationToken = default!); + Task DeactivateUser(AuditUserDetails auditUserDetails, string email, CancellationToken cancellationToken = default!); + Task DeactivateUser(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken = default!); + Task GetProfile(string email, CancellationToken cancellationToken = default!); + Task UpdateProfile(AuditUserDetails auditUserDetails, string email, UpdatedUserProfile userProfile, CancellationToken cancellationToken = default!); + public Task> GetUsersAsync(Paging paging, CancellationToken cancellationToken); + Task GetUserAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetUserByEmailAsync(string email, CancellationToken cancellationToken); + + Task EditUser(AuditUserDetails auditUserDetails, EditUser user, CancellationToken cancellationToken); + Task ResendConfirmEmail(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetCurrentEmailActionUrl(string emailAddress, EmailUserActionType emailUserActionType, CancellationToken cancellationToken ); + Task GetSsoProviderForEmail(string loginEmail, CancellationToken cancellationToken); + Task GetSsoProviderById(long ssoProviderId, CancellationToken cancellationToken); + Task LinkSsoProfileToUser(AuditUserDetails auditUserDetails, User user, long ssoId, string ssoUserId, bool setEmailConfirmed, CancellationToken cancellationToken); + Task TurnOfSsoForUser(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task CreateSingleUseGuid(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetUserWithSingleUseGuid(Guid guid, CancellationToken cancellationToken); + Task SetAuthentication( AuditUserDetails auditUserDetails, UserAuthenticationDetails userAuthenticationDetails, bool setEmailConfirmed, CancellationToken cancellationToken ); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/IUserManagerMaintenance.cs b/e-suite.API.Common/e-suite.API.Common/IUserManagerMaintenance.cs new file mode 100644 index 0000000..3949646 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/IUserManagerMaintenance.cs @@ -0,0 +1,7 @@ +namespace e_suite.API.Common; + +public interface IUserManagerMaintenance +{ + Task ClearOldEmailActions(); + Task ClearOldSingleUserGuids(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/e-suite.API.Common.csproj b/e-suite.API.Common/e-suite.API.Common/e-suite.API.Common.csproj new file mode 100644 index 0000000..6a99cae --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/e-suite.API.Common.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.API.Common + enable + enable + + + + + + + + + + + + diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/EmailNotConfirmedException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/EmailNotConfirmedException.cs new file mode 100644 index 0000000..0a908b0 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/EmailNotConfirmedException.cs @@ -0,0 +1,23 @@ +namespace e_suite.API.Common.exceptions; + +public class EmailNotConfirmedException : Exception +{ + public EmailNotConfirmedException() + { + } + + public EmailNotConfirmedException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public EmailNotConfirmedException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/ExistsException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/ExistsException.cs new file mode 100644 index 0000000..e329acf --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/ExistsException.cs @@ -0,0 +1,24 @@ +namespace e_suite.API.Common.exceptions; + +public class ExistsException : Exception +{ + public ExistsException() + { + + } + + public ExistsException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public ExistsException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/InvalidEmailException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/InvalidEmailException.cs new file mode 100644 index 0000000..922eafa --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/InvalidEmailException.cs @@ -0,0 +1,25 @@ +namespace e_suite.API.Common.exceptions; + +public class InvalidEmailException : Exception +{ + public InvalidEmailException() + { + + } + + public InvalidEmailException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public InvalidEmailException(string? message, Exception? innerException) + : base(message, innerException) + { + } + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/InvalidReferanceObjectId.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/InvalidReferanceObjectId.cs new file mode 100644 index 0000000..dfe6de6 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/InvalidReferanceObjectId.cs @@ -0,0 +1,16 @@ +namespace e_suite.API.Common.exceptions; + +public class InvalidReferenceObjectId : Exception +{ + public InvalidReferenceObjectId() + { + } + + public InvalidReferenceObjectId(string? message) : base(message) + { + } + + public InvalidReferenceObjectId(string? message, Exception? innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/MaximumRangeException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/MaximumRangeException.cs new file mode 100644 index 0000000..f2152d3 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/MaximumRangeException.cs @@ -0,0 +1,24 @@ +namespace e_suite.API.Common.exceptions; + +public class MaximumRangeException : Exception +{ + public MaximumRangeException() : base() + { + + } + + public MaximumRangeException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public MaximumRangeException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/MinimumRangeException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/MinimumRangeException.cs new file mode 100644 index 0000000..7c5c681 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/MinimumRangeException.cs @@ -0,0 +1,24 @@ +namespace e_suite.API.Common.exceptions; + +public class MinimumRangeException : Exception +{ + public MinimumRangeException() : base() + { + + } + + public MinimumRangeException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public MinimumRangeException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/NotFoundException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/NotFoundException.cs new file mode 100644 index 0000000..26309e8 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/NotFoundException.cs @@ -0,0 +1,24 @@ +namespace e_suite.API.Common.exceptions; + +public class NotFoundException : Exception +{ + public NotFoundException() + { + + } + + public NotFoundException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public NotFoundException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/TokenInvalidException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/TokenInvalidException.cs new file mode 100644 index 0000000..7df7a2e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/TokenInvalidException.cs @@ -0,0 +1,25 @@ +namespace e_suite.API.Common.exceptions; + +public class TokenInvalidException : Exception +{ + public TokenInvalidException() + { + + } + + public TokenInvalidException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public TokenInvalidException(string? message, Exception? innerException) + : base(message, innerException) + { + } + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/exceptions/WeakPasswordException.cs b/e-suite.API.Common/e-suite.API.Common/exceptions/WeakPasswordException.cs new file mode 100644 index 0000000..feaa747 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/exceptions/WeakPasswordException.cs @@ -0,0 +1,23 @@ +namespace e_suite.API.Common.exceptions; + +public class WeakPasswordException : Exception +{ + public WeakPasswordException() + { + } + + public WeakPasswordException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public WeakPasswordException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} diff --git a/e-suite.API.Common/e-suite.API.Common/extensions/ConfigurationHelper.cs b/e-suite.API.Common/e-suite.API.Common/extensions/ConfigurationHelper.cs new file mode 100644 index 0000000..8b88293 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/extensions/ConfigurationHelper.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Configuration; + +namespace e_suite.API.Common.extensions; + +public static class ConfigurationHelper +{ + public static T? GetConfigValue(this IConfiguration configuration, string environmentVariable, string key, T defaultValue) + { + var envVariable = Environment.GetEnvironmentVariable(environmentVariable); + + if (!string.IsNullOrWhiteSpace(envVariable)) + return (T?)Convert.ChangeType(envVariable, typeof(T)); + + return configuration.GetValue(key, defaultValue); + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/extensions/ObjectExtensions.cs b/e-suite.API.Common/e-suite.API.Common/extensions/ObjectExtensions.cs new file mode 100644 index 0000000..9476c7b --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/extensions/ObjectExtensions.cs @@ -0,0 +1,16 @@ +#pragma warning disable IDE0130 // Namespace does not match folder structure +namespace System; +#pragma warning restore IDE0130 // Namespace does not match folder structure + +public static class ObjectExtensions +{ + public static T DeepClone(this T obj) + { + using var stream = new MemoryStream(); + var serializer = new Xml.Serialization.XmlSerializer(typeof(T)); + + serializer.Serialize(stream, obj); + stream.Position = 0; + return (T)serializer.Deserialize(stream)!; + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/AddRoleSecurityAccess.cs b/e-suite.API.Common/e-suite.API.Common/models/AddRoleSecurityAccess.cs new file mode 100644 index 0000000..32b296a --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/AddRoleSecurityAccess.cs @@ -0,0 +1,10 @@ +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; + +namespace e_suite.API.Common.models; + +public class AddRoleSecurityAccess +{ + public GeneralIdRef RoleId { get; set; } = null!; + public List SecurityAccess { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/AuditLogEntry.cs b/e-suite.API.Common/e-suite.API.Common/models/AuditLogEntry.cs new file mode 100644 index 0000000..f2f1d81 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/AuditLogEntry.cs @@ -0,0 +1,27 @@ +using e_suite.Database.Audit.Models; + +namespace e_suite.API.Common.models; + +public class AuditLogEntry : IId +{ + public long Id { get; set; } + + public long UserId { get; set; } + public string UserDisplayName { get; set; } = string.Empty; + + public string Type { get; set; } = string.Empty; + + public DateTimeOffset DateTime { get; set; } + + public string Fields { get; set; } = string.Empty; + + public string Comment { get; set; } = string.Empty; + + public string EntityName { get; set; } = string.Empty; + + public string PrimaryKey { get; set; } = string.Empty; + + public string EntityDisplayName { get; set; } = string.Empty; + + public string DisplayName { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/AuditParams.cs b/e-suite.API.Common/e-suite.API.Common/models/AuditParams.cs new file mode 100644 index 0000000..71d63d9 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/AuditParams.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class AuditParams +{ + [JsonPropertyName("entityName")] + public string EntityName { get; set; } = string.Empty; + + [JsonPropertyName("primaryKey")] + public string PrimaryKey { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/BlockedIPs.cs b/e-suite.API.Common/e-suite.API.Common/models/BlockedIPs.cs new file mode 100644 index 0000000..8a868b1 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/BlockedIPs.cs @@ -0,0 +1,13 @@ +namespace e_suite.API.Common.models; + +public class BlockedIPs +{ + public string IPAddress { get; set; } = string.Empty; + + public int NumberOfAttempts { get; set; } + + public DateTimeOffset BlockedAt { get; set; } + + public int UnblockedIn { get; set; } + +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateContact.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateContact.cs new file mode 100644 index 0000000..45bcd2c --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateContact.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class CreateContact +{ + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } + + [JsonPropertyName("jCard")] + public string JCard { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateCustomField.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateCustomField.cs new file mode 100644 index 0000000..fe4a664 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateCustomField.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class CreateCustomField : CustomFieldBase +{ + + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } = System.Guid.NewGuid(); + +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateDomain.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateDomain.cs new file mode 100644 index 0000000..9b36876 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateDomain.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class CreateDomain : DomainBase +{ + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateFormInstance.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateFormInstance.cs new file mode 100644 index 0000000..fe33f1f --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateFormInstance.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class CreateFormInstance +{ + [JsonPropertyName("templateId")] + public GeneralIdRef TemplateId { get; set; } = null!; + + [JsonPropertyName("version")] + public long Version { get; set; } + + [JsonPropertyName("customFieldValues")] + public List CustomFieldValues { get; set; } = new(); + + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateFormTemplate.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateFormTemplate.cs new file mode 100644 index 0000000..3275179 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateFormTemplate.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class CreateFormTemplate +{ + [JsonPropertyName("name")] + [Required] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("definition")] + public string Definition { get; set; } = string.Empty; + + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateOrganisation.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateOrganisation.cs new file mode 100644 index 0000000..71fc3c4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateOrganisation.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class CreateOrganisation +{ + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } + [JsonPropertyName("name")] + [Required] + public string Name { get; set; } = string.Empty; + [JsonPropertyName("address")] + [Required] + public string Address { get; set; } = string.Empty; + [JsonPropertyName("status")] + [Required] + public OrganisationStatus Status { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateRole.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateRole.cs new file mode 100644 index 0000000..4e06a07 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateRole.cs @@ -0,0 +1,13 @@ +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class CreateRole : RoleBase +{ + public Guid? Guid { get; set; } + public bool IsSuperUser { get; set; } + public bool IsAdministrator { get; set; } + public bool CanDelete { get; set; } = true; + public GeneralIdRef DomainId { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateSite.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateSite.cs new file mode 100644 index 0000000..2ea07b5 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateSite.cs @@ -0,0 +1,8 @@ +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class CreateSite : SiteBase +{ + public Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateSpecification.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateSpecification.cs new file mode 100644 index 0000000..95ccfae --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateSpecification.cs @@ -0,0 +1,8 @@ +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class CreateSpecification : SpecificationBase +{ + public Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CreateSsoProvider.cs b/e-suite.API.Common/e-suite.API.Common/models/CreateSsoProvider.cs new file mode 100644 index 0000000..39c9cd8 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CreateSsoProvider.cs @@ -0,0 +1,8 @@ +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class CreateSsoProvider : SsoProviderBase +{ + public Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValue.cs b/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValue.cs new file mode 100644 index 0000000..375a3a9 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValue.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class CustomFieldValue +{ + /// + /// Value can be either a string or a GeneralRefId + /// + [JsonPropertyName("value")] + public object Value { get; set; } = null!; + + [JsonPropertyName("displayValue")] + public string? DisplayValue { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValueExtensions.cs b/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValueExtensions.cs new file mode 100644 index 0000000..63a6c53 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValueExtensions.cs @@ -0,0 +1,28 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public static class CustomFieldValueExtensions +{ + public static List ToCustomFieldsValues(this IEnumerable values) + { + var items = new Dictionary(); + foreach (var value in values) + { + if (!items.ContainsKey(value.Id)) + { + var newCustomFieldValues = new CustomFieldValues + { + Id = value.Id + }; + newCustomFieldValues.Values.AddRange(value.Values); + + items.Add(value.Id, newCustomFieldValues); + } + } + + var result = new List(); + result.AddRange(items.Values); + return result; + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValues.cs b/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValues.cs new file mode 100644 index 0000000..e730d9b --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/CustomFieldValues.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class CustomFieldValues +{ + [JsonPropertyName("id")] + public GeneralIdRef Id { get; set; } = new(); + + [JsonPropertyName("values")] + + public List Values { get; set; } = new(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/DeleteRoleSecurityAccess.cs b/e-suite.API.Common/e-suite.API.Common/models/DeleteRoleSecurityAccess.cs new file mode 100644 index 0000000..e5b76e1 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/DeleteRoleSecurityAccess.cs @@ -0,0 +1,10 @@ +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; + +namespace e_suite.API.Common.models; + +public class DeleteRoleSecurityAccess +{ + public GeneralIdRef RoleId { get; set; } = null!; + public List SecurityAccess { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditContact.cs b/e-suite.API.Common/e-suite.API.Common/models/EditContact.cs new file mode 100644 index 0000000..e706b02 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditContact.cs @@ -0,0 +1,9 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditContact +{ + public GeneralIdRef GeneralIdRef { get; set; } = null!; + public string JCard { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditCustomFields.cs b/e-suite.API.Common/e-suite.API.Common/models/EditCustomFields.cs new file mode 100644 index 0000000..f2c1052 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditCustomFields.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditCustomFields : CustomFieldBase +{ + [JsonPropertyName("id")] + public GeneralIdRef Id { get; set; } = new GeneralIdRef(); + +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditDomain.cs b/e-suite.API.Common/e-suite.API.Common/models/EditDomain.cs new file mode 100644 index 0000000..f4d1d2b --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditDomain.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditDomain : DomainBase +{ + [Required] + [JsonPropertyName("id")] + public GeneralIdRef Id { get; set; } = new GeneralIdRef(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditFormInstance.cs b/e-suite.API.Common/e-suite.API.Common/models/EditFormInstance.cs new file mode 100644 index 0000000..ff00f47 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditFormInstance.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; +using e_suite.Database.Core.Extensions; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditFormInstance +{ + public EditFormInstance() + { + + } + + public EditFormInstance(ReadFormInstance readFormInstance) + { + FormInstanceId = readFormInstance.ToGeneralIdRef()!; + TemplateId = readFormInstance.TemplateId; + Version = readFormInstance.Version; + foreach (var values in readFormInstance.CustomFieldValues) + { + CustomFieldValues.Add(values.DeepClone()); + } + } + + [JsonPropertyName("formInstanceId")] + public GeneralIdRef FormInstanceId { get; set; } = null!; + + [JsonPropertyName("templateId")] + public GeneralIdRef TemplateId { get; set; } = null!; + + [JsonPropertyName("version")] + public long Version { get; set; } + + [JsonPropertyName("customFieldValues")] + public List CustomFieldValues { get; set; } = []; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditFormTemplate.cs b/e-suite.API.Common/e-suite.API.Common/models/EditFormTemplate.cs new file mode 100644 index 0000000..b261133 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditFormTemplate.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditFormTemplate +{ + [Required] + [JsonPropertyName("id")] + public GeneralIdRef Id { get; set; } = new GeneralIdRef(); + + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("definition")] + public string Definition { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditGlossaryItem.cs b/e-suite.API.Common/e-suite.API.Common/models/EditGlossaryItem.cs new file mode 100644 index 0000000..959dcfe --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditGlossaryItem.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditGlossaryItem : EditableGlossaryItem +{ + [JsonPropertyName("id")] + public GeneralIdRef Id { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditOrganisation.cs b/e-suite.API.Common/e-suite.API.Common/models/EditOrganisation.cs new file mode 100644 index 0000000..17eecc4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditOrganisation.cs @@ -0,0 +1,12 @@ +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditOrganisation +{ + public GeneralIdRef GeneralIdRef { get; set; } = null!; + public string Name { get; set; } = string.Empty; + public string Address { get; set; } = string.Empty; + public OrganisationStatus Status { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditRole.cs b/e-suite.API.Common/e-suite.API.Common/models/EditRole.cs new file mode 100644 index 0000000..f497c3a --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditRole.cs @@ -0,0 +1,9 @@ +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditRole : RoleBase +{ + public GeneralIdRef GeneralIdRef { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditSite.cs b/e-suite.API.Common/e-suite.API.Common/models/EditSite.cs new file mode 100644 index 0000000..5b5f2dd --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditSite.cs @@ -0,0 +1,9 @@ +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditSite : SiteBase +{ + public GeneralIdRef Id { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditSpecification.cs b/e-suite.API.Common/e-suite.API.Common/models/EditSpecification.cs new file mode 100644 index 0000000..4c6ad7e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditSpecification.cs @@ -0,0 +1,9 @@ +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditSpecification : SpecificationBase +{ + public GeneralIdRef Id { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditSsoProvider.cs b/e-suite.API.Common/e-suite.API.Common/models/EditSsoProvider.cs new file mode 100644 index 0000000..548a595 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditSsoProvider.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditSsoProvider : SsoProviderBase +{ + [Required] + public GeneralIdRef Id { get; set; } = new GeneralIdRef(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditUser.cs b/e-suite.API.Common/e-suite.API.Common/models/EditUser.cs new file mode 100644 index 0000000..bb17d39 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditUser.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class EditUser : UserBase +{ + [JsonPropertyName("id")] + [Required] + [DefaultValue(null)] + public GeneralIdRef? Id { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EditableGlossaryItem.cs b/e-suite.API.Common/e-suite.API.Common/models/EditableGlossaryItem.cs new file mode 100644 index 0000000..495aefa --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EditableGlossaryItem.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public abstract class EditableGlossaryItem : GlossaryItemBase +{ + [JsonPropertyName("parent")] + public GeneralIdRef Parent { get; set; } = null!; + + [JsonPropertyName("childCustomFieldDefinition")] + public List ChildCustomFieldDefinition { get; set; } = new(); + + [JsonPropertyName("customFieldValues")] + public List CustomFieldValues { get; set; } = new(); + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/EmailActionToken.cs b/e-suite.API.Common/e-suite.API.Common/models/EmailActionToken.cs new file mode 100644 index 0000000..21fea39 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/EmailActionToken.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class EmailActionToken +{ + [JsonPropertyName("email")] + [Required] + public string Email { get; set; } = string.Empty; + + [JsonPropertyName("token")] + [Required] + public Guid Token { get; set; } + + [JsonPropertyName("password")] + public string Password { get; set; } = string.Empty; + + [JsonPropertyName("emailActionType")] + public EmailUserActionType EmailActionType { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ExceptionLog.cs b/e-suite.API.Common/e-suite.API.Common/models/ExceptionLog.cs new file mode 100644 index 0000000..ac56376 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ExceptionLog.cs @@ -0,0 +1,18 @@ +namespace e_suite.API.Common.models; + +public class ExceptionLog +{ + public long Id { get; set; } + + public string Application { get; set; } = string.Empty; + + public string ExceptionJson { get; set; } = string.Empty; + + public string Message { get; set; } = string.Empty; + + public string StackTrace { get; set; } = string.Empty; + + public string SupportingData { get; set; } = string.Empty; + + public DateTimeOffset OccuredAt { get; set; } +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetCustomField.cs b/e-suite.API.Common/e-suite.API.Common/models/GetCustomField.cs new file mode 100644 index 0000000..08a45be --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetCustomField.cs @@ -0,0 +1,22 @@ +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class CustomFieldDefinition +{ + public long Id { get; set; } + + public string Name { get; set; } = string.Empty; + + public FieldType FieldType { get; set; } + + public string DefaultValue { get; set; } = string.Empty; + + public long MinEntries { get; set; } = 1; + public long? MaxEntries { get; set; } + + public IGeneralIdRef? RefElementId { get; set; } + public string? Parameters { get; set; } + public Guid Guid { get; set; } +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetDomain.cs b/e-suite.API.Common/e-suite.API.Common/models/GetDomain.cs new file mode 100644 index 0000000..f977ad4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetDomain.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class GetDomain : DomainBase, IGeneralId +{ + [JsonPropertyName("id")] + public long Id { get; set; } + + [JsonPropertyName("guid")] + public Guid Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetFormInstance.cs b/e-suite.API.Common/e-suite.API.Common/models/GetFormInstance.cs new file mode 100644 index 0000000..82380fc --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetFormInstance.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class GetFormInstance +{ + [JsonPropertyName("name")] + public string Name { get; set; } = String.Empty; + + [JsonPropertyName("id")] + public GeneralIdRef Id { get; set; } = new GeneralIdRef(); + + [JsonPropertyName("versionNumber")] + public int VersionNumber { get; set; } + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetFormTemplate.cs b/e-suite.API.Common/e-suite.API.Common/models/GetFormTemplate.cs new file mode 100644 index 0000000..28ee410 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetFormTemplate.cs @@ -0,0 +1,25 @@ +using System.Text.Json.Serialization; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class GetFormTemplate : IGeneralId +{ + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("definition")] + public string Definition { get; set; } = string.Empty; + + [JsonPropertyName("id")] + public long Id { get; set; } + + [JsonPropertyName("guid")] + public Guid Guid { get; set; } + + [JsonPropertyName("version")] + public long Version { get; set; } + + [JsonPropertyName("customFieldDefinitions")] + public List CustomFieldDefinitions { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetMailTemplate.cs b/e-suite.API.Common/e-suite.API.Common/models/GetMailTemplate.cs new file mode 100644 index 0000000..2b7c420 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetMailTemplate.cs @@ -0,0 +1,8 @@ +namespace e_suite.API.Common.models; + +public class GetMailTemplate +{ + public bool IsOverridden { get; set; } + public string Subject { get; set; } = string.Empty; + public string TemplateDefinition { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetRoleSecurityAccess.cs b/e-suite.API.Common/e-suite.API.Common/models/GetRoleSecurityAccess.cs new file mode 100644 index 0000000..d345d4f --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetRoleSecurityAccess.cs @@ -0,0 +1,8 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class GetRoleSecurityAccess : GetSecurityAccess +{ + public GeneralIdRef RoleId { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetSecurityAccess.cs b/e-suite.API.Common/e-suite.API.Common/models/GetSecurityAccess.cs new file mode 100644 index 0000000..8c49d1d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetSecurityAccess.cs @@ -0,0 +1,11 @@ +using eSuite.Core.Security; + +namespace e_suite.API.Common.models; + +public class GetSecurityAccess +{ + public SecurityAccess SecurityAccess { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string GroupName { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GetUser.cs b/e-suite.API.Common/e-suite.API.Common/models/GetUser.cs new file mode 100644 index 0000000..e3f00ba --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GetUser.cs @@ -0,0 +1,20 @@ +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class GetUser : UserBase +{ + public long Id { get; set; } + + public Guid Guid { get; set; } + + public string DisplayName { get; set; } = string.Empty; + + public string DomainName { get; set; } = string.Empty; + + public DateTimeOffset Created { get; set; } + + public DateTimeOffset LastUpdated { get; set; } + + public bool EmailConfirmed { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/GlossaryItem.cs b/e-suite.API.Common/e-suite.API.Common/models/GlossaryItem.cs new file mode 100644 index 0000000..585f8ed --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/GlossaryItem.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class GlossaryItem : GlossaryItemBase, IGeneralId +{ + [JsonPropertyName("id")] + public long Id { get; set; } + + [JsonPropertyName("guid")] + public Guid Guid { get; set; } + + [JsonPropertyName("childCustomFieldDefinition")] + public List? ChildCustomFieldDefinition { get; set; } + + [JsonPropertyName("children")] + public List? Children { get; set; } + + [JsonPropertyName("customFieldValues")] + public List? CustomFieldValues { get; set; } + + [JsonPropertyName("parent")] + public GlossaryItem? Parent { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/Login.cs b/e-suite.API.Common/e-suite.API.Common/models/Login.cs new file mode 100644 index 0000000..07c306d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/Login.cs @@ -0,0 +1,52 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using e_suite.Nuget.PasswordHasher; + +namespace e_suite.API.Common.models; + +/// +/// Used to pass details when trying to establish a user connection to the API. +/// +public class Login : IPassword +{ + /// + /// users registered e-mail address + /// + [JsonPropertyName("email")] + [DefaultValue("testuser@sun-strategy.com")] + [Required] + [EmailAddress] + [Display(Name = "E-Mail")] + public string Email { get; set; } = string.Empty; + + /// + /// Users password. Note, this is unencrypted and used only for comparison against the stored hashed password. + /// + [JsonPropertyName("password")] + [DefaultValue("12345 Same as my luggage")] + [Display(Name = "Password")] + [DataType(DataType.Password)] + public string Password { get; set; } = string.Empty; + + /// + /// Authenticator security code. Compatible with Google Authenticator. + /// + [JsonPropertyName("securityCode")] + [DefaultValue("")] + [Display(Name = "Security Code")] + public string SecurityCode { get; set; } = string.Empty; + + /// + /// User has lost their TFA device and needs to start the process of removing the TFA from their account. An email will be sent to the user with a link to complete the request. + /// + [JsonPropertyName("requestTfaRemoval")] + [DefaultValue(false)] + [Display(Name = "Request 2FA Removal")] + public bool RequestTfaRemoval { get; set; } = false; + + [JsonPropertyName("forgotPassword")] + [Display(Name = "Forgot Password")] + [DefaultValue(false)] + public bool ForgotPassword { get; set; } = false; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/LoginResponse.cs b/e-suite.API.Common/e-suite.API.Common/models/LoginResponse.cs new file mode 100644 index 0000000..d6512f1 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/LoginResponse.cs @@ -0,0 +1,7 @@ +namespace e_suite.API.Common.models; + +public class LoginResponse +{ + public LoginResult Result { get; set; } + public string Token { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/LoginResult.cs b/e-suite.API.Common/e-suite.API.Common/models/LoginResult.cs new file mode 100644 index 0000000..273a12d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/LoginResult.cs @@ -0,0 +1,11 @@ +namespace e_suite.API.Common.models; + +public enum LoginResult +{ + Failed, + EmailNotConfirmed, + TwoFactorAuthenticationRemovalRequested, + TwoFactorAuthenticationCodeRequired, + TwoFactorAuthenticationCodeIncorrect, + Success +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/MailTemplateType.cs b/e-suite.API.Common/e-suite.API.Common/models/MailTemplateType.cs new file mode 100644 index 0000000..ec8ac59 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/MailTemplateType.cs @@ -0,0 +1,9 @@ +using eSuite.Core.MailService; + +namespace e_suite.API.Common.models; + +public class MailTemplateType +{ + public MailType MailType { get; set; } + public string? Description { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/NewGlossaryItem.cs b/e-suite.API.Common/e-suite.API.Common/models/NewGlossaryItem.cs new file mode 100644 index 0000000..0792d78 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/NewGlossaryItem.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class NewGlossaryItem : EditableGlossaryItem +{ + [JsonPropertyName("guid")] + public Guid? Guid { get; set; } = System.Guid.NewGuid(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/NewSequence.cs b/e-suite.API.Common/e-suite.API.Common/models/NewSequence.cs new file mode 100644 index 0000000..f933383 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/NewSequence.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; + +namespace e_suite.API.Common.models; + +public class NewSequence : SequenceBase +{ + [JsonPropertyName("Guid")] + public System.Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/NumberFieldParameters.cs b/e-suite.API.Common/e-suite.API.Common/models/NumberFieldParameters.cs new file mode 100644 index 0000000..9151ec4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/NumberFieldParameters.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class NumberFieldParameters +{ + [JsonPropertyName("minValue")] + public string? MinimumValue { get; set; } + [JsonPropertyName("maxValue")] + public string? MaximumValue { get; set; } + [JsonPropertyName("step")] + public string? Step { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/PerformanceReportSummary.cs b/e-suite.API.Common/e-suite.API.Common/models/PerformanceReportSummary.cs new file mode 100644 index 0000000..da01744 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/PerformanceReportSummary.cs @@ -0,0 +1,14 @@ +namespace e_suite.API.Common.models; + +public class PerformanceReportSummary +{ + public long MaxTotalTimeMS; + public string Host { get; set; } + public string ControllerName { get; set; } + public string ActionName { get; set; } + public string RequestType { get; set; } + public object MinTotalTimeMs { get; set; } + public object AvgTotalTimeMs { get; set; } + public object SumTotalTimeMs { get; set; } + public object Count { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/PostMailTemplate.cs b/e-suite.API.Common/e-suite.API.Common/models/PostMailTemplate.cs new file mode 100644 index 0000000..8bc4aad --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/PostMailTemplate.cs @@ -0,0 +1,12 @@ +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class PostMailTemplate +{ + public GeneralIdRef Domain { get; set; } = null!; + public MailType MailType { get; set; } + public string Subject { get; set; } = string.Empty; + public string TemplateDefinition { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadContactDto.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadContactDto.cs new file mode 100644 index 0000000..88627f4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadContactDto.cs @@ -0,0 +1,9 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class ReadContact +{ + public GeneralIdRef GeneralIdRef { get; set; } = null!; + public string JCard { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadFormInstance.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadFormInstance.cs new file mode 100644 index 0000000..f23309b --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadFormInstance.cs @@ -0,0 +1,35 @@ +using System.Text.Json.Serialization; +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class ReadFormInstance : IGeneralId +{ + [JsonPropertyName("id")] + public long Id { get; set; } + + [JsonPropertyName("guid")] + public Guid Guid { get; set; } + + [JsonPropertyName("templateId")] + public GeneralIdRef TemplateId { get; set; } = null!; + + [JsonPropertyName("version")] + public long Version { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("definition")] + public string Definition { get; set; } = string.Empty; + + [JsonPropertyName("customFieldValues")] + public List CustomFieldValues { get; set; } = []; + + [JsonPropertyName("customFieldDefinitions")] + public List CustomFieldDefinitions { get; set; } = null!; + + [JsonPropertyName("updatedVersion")] + public long UpdatedVersion { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadOrganisation.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadOrganisation.cs new file mode 100644 index 0000000..9f754f4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadOrganisation.cs @@ -0,0 +1,15 @@ +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class ReadOrganisation : IGeneralId +{ + public long Id { get; set; } + public Guid Guid { get; set; } + + public string Name { get; set; } = string.Empty; + + public string Address { get; set; } = string.Empty; + + public OrganisationStatus Status { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadPerformanceReport.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadPerformanceReport.cs new file mode 100644 index 0000000..e7f2810 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadPerformanceReport.cs @@ -0,0 +1,24 @@ +using e_suite.Database.Core.Tables.Diagnostics; + +namespace e_suite.API.Common.models; + +public class ReadPerformanceReport +{ + public ReadPerformanceReport() + { + Host = string.Empty; + ControllerName = string.Empty; + ActionName = string.Empty; + } + + public ReadPerformanceReport(PerformanceReport report) + { + Host = report.Host; + ControllerName = report.ControllerName; + ActionName = report.ActionName; + } + + public string Host { get; set; } + public string ControllerName { get; set; } + public string ActionName { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadPerformanceReportSummary.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadPerformanceReportSummary.cs new file mode 100644 index 0000000..3c9683b --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadPerformanceReportSummary.cs @@ -0,0 +1,21 @@ +namespace e_suite.API.Common.models; + +public class ReadPerformanceReportSummary +{ + public ReadPerformanceReportSummary() + { + Host = string.Empty; + ControllerName = string.Empty; + ActionName = string.Empty; + } + public ReadPerformanceReportSummary(PerformanceReportSummary performanceReportSummary) + { + Host = performanceReportSummary.Host; + ControllerName = performanceReportSummary.ControllerName; + ActionName = performanceReportSummary.ActionName; + } + + public string Host { get; set; } + public string ControllerName { get; set; } + public string ActionName { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadRole.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadRole.cs new file mode 100644 index 0000000..0ef4673 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadRole.cs @@ -0,0 +1,15 @@ +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class ReadRole : RoleBase +{ + public long Id { get; set; } + public Guid Guid { get; set; } + public bool IsSuperUser { get; set; } + public bool IsAdministrator { get; set; } + public bool CanDelete { get; set; } = true; + public GeneralIdRef DomainId { get; set; } = null!; + public string DomainName { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadSequence.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadSequence.cs new file mode 100644 index 0000000..addb67e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadSequence.cs @@ -0,0 +1,8 @@ +namespace e_suite.API.Common.models; + +public class ReadSequence +{ + public string Name { get; set; } = String.Empty; + public long Id { get; set; } + public Guid Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadSite.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadSite.cs new file mode 100644 index 0000000..9a75f37 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadSite.cs @@ -0,0 +1,10 @@ +using e_suite.API.Common.models.@base; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class ReadSite : SiteBase, IGeneralId +{ + public long Id { get; set; } + public Guid Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadSpecification.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadSpecification.cs new file mode 100644 index 0000000..a10bc89 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadSpecification.cs @@ -0,0 +1,11 @@ +using e_suite.API.Common.models.@base; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class ReadSpecification : SpecificationBase, IGeneralId +{ + public long Id { get; set; } + public Guid Guid { get; set; } + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ReadSsoProvider.cs b/e-suite.API.Common/e-suite.API.Common/models/ReadSsoProvider.cs new file mode 100644 index 0000000..3fcd42c --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ReadSsoProvider.cs @@ -0,0 +1,10 @@ +using e_suite.API.Common.models.@base; +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class ReadSsoProvider : SsoProviderBase, IGeneralId +{ + public long Id { get; set; } + public Guid Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/RoleUser.cs b/e-suite.API.Common/e-suite.API.Common/models/RoleUser.cs new file mode 100644 index 0000000..b529a76 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/RoleUser.cs @@ -0,0 +1,11 @@ +using e_suite.Database.Core.Models; + +namespace e_suite.API.Common.models; + +public class RoleUser : IGeneralId +{ + public long Id { get; set; } + public Guid Guid { get; set; } + public string DisplayName { get; set; } = string.Empty; + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/Sequence.cs b/e-suite.API.Common/e-suite.API.Common/models/Sequence.cs new file mode 100644 index 0000000..dcc6215 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/Sequence.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using e_suite.API.Common.models.@base; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class Sequence : SequenceBase +{ + [JsonPropertyName("id")] + [Required] + [DefaultValue(null)] + public GeneralIdRef? GeneralIdRef { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/TextFieldParameters.cs b/e-suite.API.Common/e-suite.API.Common/models/TextFieldParameters.cs new file mode 100644 index 0000000..982be44 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/TextFieldParameters.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class TextFieldParameters +{ + [JsonPropertyName("multiLine")] + public bool MultiLine { get; set; } +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/TwoFactorAuthenticationSettings.cs b/e-suite.API.Common/e-suite.API.Common/models/TwoFactorAuthenticationSettings.cs new file mode 100644 index 0000000..50bed5a --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/TwoFactorAuthenticationSettings.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class TwoFactorAuthenticationSettings +{ + [JsonPropertyName("qrCodeImageUrl")] + public string QrCodeImageUrl { get; set; } = null!; + + [JsonPropertyName("manualEntrySetupCode")] + public string ManualEntrySetupCode { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/UserAuthenticationDetails.cs b/e-suite.API.Common/e-suite.API.Common/models/UserAuthenticationDetails.cs new file mode 100644 index 0000000..52a53c5 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/UserAuthenticationDetails.cs @@ -0,0 +1,11 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class UserAuthenticationDetails +{ + public IGeneralIdRef Id { get; set; } = null!; + public string Password { get; set; } = string.Empty; + public string SecurityCode { get; set; } = string.Empty; + public bool UsingTwoFactorAuthentication { get; set; } = false; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/UserProfile.cs b/e-suite.API.Common/e-suite.API.Common/models/UserProfile.cs new file mode 100644 index 0000000..991421f --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/UserProfile.cs @@ -0,0 +1,82 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models; + +public class UserProfile +{ + [JsonPropertyName("firstName")] + [Display(Name = "First Name")] + public string FirstName { get; set; } = string.Empty; + + [JsonPropertyName("middleNames")] + [Display(Name = "Middle Name(s)")] + public string MiddleNames { get; set; } = string.Empty; + + [JsonPropertyName("lastName")] + [Display(Name = "Last Name")] + public string LastName { get; set; } = string.Empty; + + [JsonPropertyName("email")] + [Required] + [Display(Name = "E-Mail")] + public string Email { get; set; } = string.Empty; + + [JsonPropertyName("password")] + [Display(Name = "Password")] + public string Password { get; set; } = string.Empty; + + [JsonPropertyName("usingTwoFactorAuthentication")] + [Required] + public bool UsingTwoFactorAuthentication { get; set; } + + [JsonPropertyName("created")] + public DateTimeOffset Created { get; set; } + + [JsonPropertyName("twoFactorAuthenticationSettings")] + public TwoFactorAuthenticationSettings TwoFactorAuthenticationSettings { get; set; } = null!; + + [JsonPropertyName("securityCode")] + public string SecurityCode { get; set; } = null!; + + [JsonPropertyName("domainSsoProviderId")] + + public long? DomainSsoProviderId { get; set; } = null; + + [JsonPropertyName("ssoProviderId")] + + public long? SsoProviderId { get; set; } = null; + + [JsonPropertyName("ssoSubject")] + + public string SsoSubject { get; set; } = string.Empty; + + public Dictionary SsoProviders { get; set; } = null!; +} + + +public class UpdatedUserProfile +{ + [JsonPropertyName("firstName")] + public string FirstName { get; set; } = string.Empty; + + [JsonPropertyName("middleNames")] + public string MiddleNames { get; set; } = string.Empty; + + [JsonPropertyName("lastName")] + public string LastName { get; set; } = string.Empty; + + [JsonPropertyName("email")] + [Required] + public string Email { get; set; } = string.Empty; + + [JsonPropertyName("password")] + public string Password { get; set; } = string.Empty; + + [JsonPropertyName("usingTwoFactorAuthentication")] + [Required] + public bool UsingTwoFactorAuthentication { get; set; } + + [JsonPropertyName("securityCode")] + public string SecurityCode { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/UserRegistration.cs b/e-suite.API.Common/e-suite.API.Common/models/UserRegistration.cs new file mode 100644 index 0000000..5ac9465 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/UserRegistration.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class UserRegistration +{ + [JsonPropertyName("firstName")] + [DefaultValue("Fred")] + public string FirstName { get; set; } = string.Empty; + + [JsonPropertyName("middleNames")] + [DefaultValue("")] + public string MiddleNames { get; set; } = string.Empty; + + [JsonPropertyName("lastName")] + [DefaultValue("bloggs")] + public string LastName { get; set; } = string.Empty; + + [JsonPropertyName("email")] + [DefaultValue("fred.bloggs@sun-strategy.com")] + [Required] + public string Email { get; set; } = string.Empty; + + [JsonPropertyName("domainId")] + public GeneralIdRef? DomainId { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/UserRoleIds.cs b/e-suite.API.Common/e-suite.API.Common/models/UserRoleIds.cs new file mode 100644 index 0000000..40882a2 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/UserRoleIds.cs @@ -0,0 +1,9 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models; + +public class UserRoleIds +{ + public GeneralIdRef RoleId { get; set; } = null!; + public GeneralIdRef UserId { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/ValidatedCustomFieldValue.cs b/e-suite.API.Common/e-suite.API.Common/models/ValidatedCustomFieldValue.cs new file mode 100644 index 0000000..e6f491e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/ValidatedCustomFieldValue.cs @@ -0,0 +1,14 @@ +using e_suite.Database.Core.Tables.CustomFields; + +namespace e_suite.API.Common.models; + +public class ValidatedCustomFieldValue +{ + public CustomField CustomField { get; set; } = null!; + public long CustomFieldId { get; set; } + public int Index { get; set; } + public string Value { get; set; } = string.Empty; + public string? DisplayValue { get; set; } = string.Empty; + public bool Valid => ValidationErrors.Count == 0; + public List ValidationErrors { get; set; } = new List(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/CustomFieldBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/CustomFieldBase.cs new file mode 100644 index 0000000..721938d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/CustomFieldBase.cs @@ -0,0 +1,29 @@ +using System.Text.Json.Serialization; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models.@base; + +public abstract class CustomFieldBase +{ + [JsonPropertyName("fieldType")] + public FieldType FieldType { get; set; } + + [JsonPropertyName("refElementId")] + public GeneralIdRef? RefElementId { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("defaultValue")] + public string DefaultValue { get; set; } = string.Empty; + + [JsonPropertyName("minEntries")] + public long MinEntries { get; set; } + + [JsonPropertyName("maxEntries")] + public long? MaxEntries { get; set; } + + [JsonPropertyName("params")] + public string Parameters { get; set; } = string.Empty; +} diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/DomainBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/DomainBase.cs new file mode 100644 index 0000000..64bf284 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/DomainBase.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models.@base; + +public abstract class DomainBase +{ + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("sunriseHostName")] + public string SunriseHostName { get; set; } = string.Empty; + + [JsonPropertyName("sunriseAppId")] + public string SunriseAppId { get; set; } = string.Empty; + + [JsonPropertyName("sunriseCategoryId")] + public string SunriseCategoryId { get; set; } = string.Empty; + + [JsonPropertyName("ssoProviderId")] + public GeneralIdRef? SsoProviderId { get; set; } = null; + + [JsonPropertyName("sigmaId")] + public long? SigmaId { get; set; } = null; + +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/GlossaryItemBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/GlossaryItemBase.cs new file mode 100644 index 0000000..69b18ca --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/GlossaryItemBase.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace e_suite.API.Common.models.@base; + +public abstract class GlossaryItemBase +{ + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/RoleBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/RoleBase.cs new file mode 100644 index 0000000..7a2980a --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/RoleBase.cs @@ -0,0 +1,6 @@ +namespace e_suite.API.Common.models.@base; + +public abstract class RoleBase +{ + public string Name { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/SequenceBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/SequenceBase.cs new file mode 100644 index 0000000..5452dc0 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/SequenceBase.cs @@ -0,0 +1,75 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using eSuite.Core.Sequences; + +namespace e_suite.API.Common.models.@base; + +public abstract class SequenceBase : IValidatableObject +{ + private static readonly Regex YearPlaceholderExpression = + new(@"\{(YY|YYYY)\}", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + private static readonly Regex MonthPlaceholderExpression = + new(@"\{MM\}", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + private static readonly Regex DayPlaceholderExpression = + new(@"\{DD\}", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + private static readonly Regex NumericPlaceholderExpression = + new(@"\[0+\]", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + [JsonPropertyName("name")] + [Required] + [DefaultValue("Sequence name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("seed")] + [Required] + [DefaultValue(1)] + public long Seed { get; set; } + + [JsonPropertyName("increment")] + [Required] + [DefaultValue(1)] + public long Increment { get; set; } + + [JsonPropertyName("pattern")] + [Required] + [DefaultValue("[0]")] + public string Pattern { get; set; } = "[0]"; + + [JsonPropertyName("rolloverType")] + [Required] + [DefaultValue(Rollover.Continuous)] + public Rollover RolloverType { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (RolloverType == Rollover.Day && !DayPlaceholderExpression.IsMatch(Pattern)) + { + yield return new ValidationResult("When the rollover type is set to 'Daily', then the pattern must include either a {DD} placeholder", new string[] { nameof(Pattern) }); + } + + if (RolloverType == Rollover.Month && !MonthPlaceholderExpression.IsMatch(Pattern)) + { + yield return new ValidationResult("When the rollover type is set to 'Monthly', then the pattern must include either a {MM} placeholder", new string[] { nameof(Pattern) }); + } + + if (RolloverType == Rollover.Year && !YearPlaceholderExpression.IsMatch(Pattern)) + { + yield return new ValidationResult("When the rollover type is set to 'Annual', then the pattern must include either a {YY} or {YYYY} placeholder", new string[] { nameof(Pattern) }); + } + + if (!NumericPlaceholderExpression.IsMatch(Pattern)) + { + yield return new ValidationResult("At minimum all patterns must contain one numeric value (i.e. [0])", new string[] { nameof(Pattern) }); + } + + if (Increment == 0) + { + yield return new ValidationResult("Increment can not be 0", new string[] { nameof(Increment) }); + } + } +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/SiteBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/SiteBase.cs new file mode 100644 index 0000000..ad0432f --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/SiteBase.cs @@ -0,0 +1,13 @@ +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models.@base; + +public abstract class SiteBase +{ + public string Name { get; set; } = string.Empty; + public string Address { get; set; } = string.Empty; + public OrganisationStatus Status { get; set; } + public GeneralIdRef OrganisationId { get; set; } = null!; + public long? SigmaId { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/SpecificationBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/SpecificationBase.cs new file mode 100644 index 0000000..08c3d2d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/SpecificationBase.cs @@ -0,0 +1,11 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models.@base; + +public class SpecificationBase +{ + public string Name { get; set; } = string.Empty; + public GeneralIdRef FormInstanceId { get; set; } = null!; + public GeneralIdRef Site { get; set; } = null!; + public long? SigmaId { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/SsoProviderBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/SsoProviderBase.cs new file mode 100644 index 0000000..1be6846 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/SsoProviderBase.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; + +namespace e_suite.API.Common.models.@base; + +public class SsoProviderBase +{ + [Required] + public string Name { get; set; } = string.Empty; + + [Required] + public string ClientId { get; set; } = string.Empty; + + [Required] + public string ClientSecret { get; set; } = string.Empty; + + [Required] + public string ValidIssuer { get; set; } = string.Empty; + + [Required] + public string AuthorizationEndpoint { get; set; } = string.Empty; + + [Required] + public string TokenEndpoint { get; set; } = string.Empty; + + public bool IsPublic { get; set; } = true; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/models/base/UserBase.cs b/e-suite.API.Common/e-suite.API.Common/models/base/UserBase.cs new file mode 100644 index 0000000..f26b1e5 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/models/base/UserBase.cs @@ -0,0 +1,16 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.models.@base; + +public abstract class UserBase +{ + public string FirstName { get; set; } = string.Empty; + + public string LastName { get; set; } = string.Empty; + + public string MiddleNames { get; set; } = string.Empty; + + public string Email { get; set; } = string.Empty; + + public GeneralIdRef Domain { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IAuditLogRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IAuditLogRepository.cs new file mode 100644 index 0000000..4bbc694 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IAuditLogRepository.cs @@ -0,0 +1,9 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit.Tables.Audit; + +namespace e_suite.API.Common.repository; + +public interface IAuditLogRepository +{ + IQueryable GetAuditEntries(AuditParams? auditParams, bool primaryOnly); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IBlockedIPsManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IBlockedIPsManagerRepository.cs new file mode 100644 index 0000000..0428d0e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IBlockedIPsManagerRepository.cs @@ -0,0 +1,11 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using FailedAccessAttempt = e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt; + +namespace e_suite.API.Common.repository; +public interface IBlockedIPsManagerRepository: IRepository +{ + IQueryable GetBlockedIPs(DateTimeOffset earliestAttemptTime); + + Task UnBlockIP(AuditUserDetails auditUserDetails, string ipAddress, CancellationToken cancellationToken); +} diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IContactsManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IContactsManagerRepository.cs new file mode 100644 index 0000000..a8a7111 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IContactsManagerRepository.cs @@ -0,0 +1,16 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Contacts; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IContactsManagerRepository : IRepository +{ + Task AddContact(AuditUserDetails auditUserDetails, Contact contact, CancellationToken cancellationToken); + Task EditContact(AuditUserDetails auditUserDetails, Contact contact, CancellationToken cancellationToken); + Task GetContact(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task LinkContactToOrganisation(AuditUserDetails auditUserDetails, OrganisationContact organisationContact, CancellationToken cancellationToken); + Task LinkContactToSite(AuditUserDetails auditUserDetails, SiteContact siteContact, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldReferenceObjectRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldReferenceObjectRepository.cs new file mode 100644 index 0000000..f8be910 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldReferenceObjectRepository.cs @@ -0,0 +1,51 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using Sequence = e_suite.Database.Core.Tables.Sequences.Sequence; + +namespace e_suite.API.Common.repository; + +public interface ICustomFieldReferenceObjectRepository +{ + Task GetSequenceByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + + Task GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + + Task GetGlossaryByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + + Task GetDomainByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken); + + Task CreateFormReferenceAsync(AuditUserDetails auditUserDetails, long customFieldId, long formId, CancellationToken cancellationToken); + Task CreateGlossaryReferenceAsync(AuditUserDetails auditUserDetails, long customField, long formId, CancellationToken cancellationToken); + Task CreateDomainReferenceAsync(AuditUserDetails auditUserDetails, long customField, long formId, CancellationToken cancellationToken); + Task CreateSequenceReferenceAsync(AuditUserDetails auditUserDetails, long customField, long formId, CancellationToken cancellationToken); + + Task DeleteFormReferenceAsync(AuditUserDetails auditUserDetails, long customFieldId, CancellationToken cancellationToken); + Task DeleteGlossaryReferenceAsync(AuditUserDetails auditUserDetails, long customField, CancellationToken cancellationToken); + Task DeleteDomainReferenceAsync(AuditUserDetails auditUserDetails, long customField, CancellationToken cancellationToken); + Task DeleteSequenceReferenceAsync(AuditUserDetails auditUserDetails, long customFiled, CancellationToken cancellationToken); + + Task EditFormReferenceAsync(AuditUserDetails auditUserDetails,CustomFieldFormTemplate customFieldFormTemplate, CancellationToken cancellationToken); + Task EditGlossaryReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldGlossary customFieldGlossary, CancellationToken cancellationToken); + Task EditDomainReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldGlossary customFieldGlossary, CancellationToken cancellationToken); + Task EditSequenceReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldSequence customFieldSequence, CancellationToken cancellationToken); + + Task GetFormReferenceAsync(long customFieldId, CancellationToken cancellationToken); + + Task GetSequenceReferenceAsync(long customFieldId, CancellationToken cancellationToken); + + Task GetGlossaryReferenceAsync(long cusotmFieldId, CancellationToken cancellationToken); + Task GetNumbersParametersAsync(long customFieldId, CancellationToken cancellationToken); + Task CreateCustomFieldNumbersAsync(AuditUserDetails auditUserDetails, CustomFieldNumber customFieldNumber, CancellationToken cancellationToken); + Task EditCustomFieldNumbersAsync(AuditUserDetails auditUserDetails, CustomFieldNumber customFieldNumber, NumberFieldParameters numberFieldParameters, CancellationToken cancellationToken); + Task DeleteCustomFieldNumbersAsync(AuditUserDetails auditUserDetails, CustomFieldNumber customFieldNumber, CancellationToken cancellationToken); + + Task GetTextsParametersAsync(long customFieldId, CancellationToken cancellationToken); + Task CreateCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, CancellationToken cancellationToken); + Task EditCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, TextFieldParameters textFieldParameters, CancellationToken cancellationToken); + Task DeleteCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldRepository.cs new file mode 100644 index 0000000..7eaac52 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldRepository.cs @@ -0,0 +1,18 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.CustomFields; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface ICustomFieldRepository : IRepository +{ + Task GetByIdAsync(IGeneralIdRef id, CancellationToken cancellationToken); + + Task GetByNameAsync(string name, CancellationToken cancellationToken); + Task EditAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken); + + Task CreateAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken); + + IQueryable GetCustomFieldList(); +} diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldValidatorRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldValidatorRepository.cs new file mode 100644 index 0000000..f5d5eed --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ICustomFieldValidatorRepository.cs @@ -0,0 +1,18 @@ +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface ICustomFieldValidatorRepository : IRepository +{ + Task FindSequenceIdForCustomField(long customFieldId, CancellationToken cancellationToken); + Task GetTemplateByGeneralRefId(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetGlossaryByGeneralRefId(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetDomainByGeneralRefId(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetCustomFieldNumbersAsync(long fieldId, CancellationToken cancellationToken); + Task GetCustomFieldTextsAsync(long fieldId, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IDomainRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IDomainRepository.cs new file mode 100644 index 0000000..7758b91 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IDomainRepository.cs @@ -0,0 +1,16 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Domain; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IDomainRepository : IRepository +{ + IQueryable GetDomains(); + Task GetDomainById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetDomainByName(string domainName, CancellationToken cancellationToken); + Task EditDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken); + Task CreateDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken); + Task AddAdministratorRoleAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IExceptionLogRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IExceptionLogRepository.cs new file mode 100644 index 0000000..72db500 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IExceptionLogRepository.cs @@ -0,0 +1,10 @@ +using e_suite.Database.Core.Tables.Diagnostics; + +namespace e_suite.API.Common.repository; + +public interface IExceptionLogRepository +{ + Task LogException(ExceptionLog exception, CancellationToken cancellationToken); + + IQueryable GetExceptionLogs(); +} diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IFormRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IFormRepository.cs new file mode 100644 index 0000000..337c56e --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IFormRepository.cs @@ -0,0 +1,31 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IFormRepository : IRepository +{ + //FormTemplate + Task GetTemplateAsync(IGeneralIdRef id, CancellationToken cancellationToken); + Task GetTemplateWithOutLoadedRefereranceAsync(IGeneralIdRef id, CancellationToken cancellationToken); + Task CreateTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate template, CancellationToken cancellationToken); + IQueryable GetTemplates(); + Task DeleteAllVersionsAsync(AuditUserDetails auditUserDetails, IEnumerable formTemplateVersions, CancellationToken cancellationToken); + Task EditFormTemplateAsync(AuditUserDetails auditUserDetails,FormTemplate formTemplate, CancellationToken cancellationToken); + Task CreateNewFormVersionAsync(AuditUserDetails auditUserDetails, FormTemplateVersion formTemplateVersion, CancellationToken cancellationToken); + IQueryable GetAllFormVersions(long templateId); + Task GetFormTemplateVersionAsync(IGeneralIdRef id, CancellationToken cancellationToken); + Task GetFormTemplateWithSpecificVersionAsync(IGeneralIdRef id, long formTemplateVersionId, CancellationToken cancellationToken); + + //FormInstances + Task AddFormInstance(AuditUserDetails auditUserDetails, FormInstance newFormInstance, CancellationToken cancellationToken); + Task AddFormInstances(AuditUserDetails auditUserDetails, IEnumerable newFormInstance, CancellationToken cancellationToken); + Task AddFormInstanceValues(AuditUserDetails auditUserDetails, List customFieldValues, CancellationToken cancellationToken); + Task GetFormInstance(GeneralIdRef createFormInstanceId, bool tracking, CancellationToken cancellationToken); + Task> GetFormInstances(IEnumerable generalIdRefs, bool tracking, CancellationToken cancellationToken); + Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken); + Task> GetFormsContainingFieldValue(IGeneralIdRef customFieldGeneralIdRef, string value, CancellationToken cancellationToken); +} diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IGlossariesManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IGlossariesManagerRepository.cs new file mode 100644 index 0000000..6c9c34d --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IGlossariesManagerRepository.cs @@ -0,0 +1,25 @@ +using e_suite.Database.Audit; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IGlossariesManagerRepository : IRepository +{ + Task AddGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossary, CancellationToken cancellationToken); + Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable items, CancellationToken cancellationToken); + Task EditGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossaryItem, CancellationToken cancellationToken); + Task FindGlossary(IGeneralIdRef glossaryItem, CancellationToken cancellationToken); + Task> FindGlossaryChildren(long parentId, CancellationToken cancellationToken); + Task> GetCustomFieldDefinitions(IEnumerable customFieldIdRefs, CancellationToken cancellationToken); + Task GetParentGlossary(IGeneralIdRef? glossaryItemParent, CancellationToken cancellationToken); + IQueryable GetGlossaryCustomFields(long glossaryId); + Task SaveChildCustomFieldDefinitions(AuditUserDetails auditUserDetails, IReadOnlyList removalList, IReadOnlyList additionList, CancellationToken cancellationToken); + Task> GetGlossaryCustomValues(IId glossary, CancellationToken cancellationToken); + Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken); + Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable> deltas, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IMailServiceRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IMailServiceRepository.cs new file mode 100644 index 0000000..d08e0a7 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IMailServiceRepository.cs @@ -0,0 +1,10 @@ +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Mail; +using eSuite.Core.MailService; + +namespace e_suite.API.Common.repository; + +public interface IMailServiceRepository : IRepository +{ + Task GetMailTemplate(long domainId, MailType emailRequestEmailType, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IMailTemplatesManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IMailTemplatesManagerRepository.cs new file mode 100644 index 0000000..01ea25b --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IMailTemplatesManagerRepository.cs @@ -0,0 +1,15 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Mail; +using eSuite.Core.MailService; + +namespace e_suite.API.Common.repository; + +public interface IMailTemplatesManagerRepository : IRepository +{ + Task GetMailTemplate(long domainId, MailType emailRequestEmailType, CancellationToken cancellationToken); + Task InsertMailTemplateAsync(MailTemplate template, AuditUserDetails auditUserDetails, + CancellationToken cancellationToken); + Task UpdateMailTemplateAsync(MailTemplate template, AuditUserDetails auditUserDetails, + CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IOrganisationsManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IOrganisationsManagerRepository.cs new file mode 100644 index 0000000..90948e6 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IOrganisationsManagerRepository.cs @@ -0,0 +1,15 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IOrganisationsManagerRepository : IRepository +{ + IQueryable GetOrganisationsList(); + Task AddOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken); + Task DeleteOrganisation(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task EditOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken); + Task FindOrganisation(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IPerformanceManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IPerformanceManagerRepository.cs new file mode 100644 index 0000000..6c31866 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IPerformanceManagerRepository.cs @@ -0,0 +1,10 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.Diagnostics; + +namespace e_suite.API.Common.repository; + +public interface IPerformanceManagerRepository +{ + IQueryable GetPerformanceReportSummary(); + IQueryable GetPerformanceReports(string hostName, string controllerName, string actionName, string requestType); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IRoleManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IRoleManagerRepository.cs new file mode 100644 index 0000000..5feb5d6 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IRoleManagerRepository.cs @@ -0,0 +1,23 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IRoleManagerRepository : IRepository +{ + IQueryable GetRolesList(); + Task GetRoleById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetRoleByName(Domain domain, string sequenceName, CancellationToken cancellationToken); + Task EditRole(AuditUserDetails auditUserDetails, Role existingSequence, CancellationToken cancellationToken); + Task AddRole(AuditUserDetails auditUserDetails, Role existingSequence, CancellationToken cancellationToken); + IQueryable GetUserRoles(); + Task AddUserRole(AuditUserDetails auditUserDetails, Role existingRole, User existingUser, CancellationToken cancellationToken); + Task DeleteUserRole(AuditUserDetails auditUserDetails, Role existingRole, User existingUser, CancellationToken cancellationToken); + IQueryable GetAccessForRole(); + Task AddSecurityAccess(AuditUserDetails auditUserDetails, List rollAccessToAdd, CancellationToken cancellationToken); + Task DeleteSecurityAccess(AuditUserDetails auditUserDetails, List rollAccessToAdd, CancellationToken cancellationToken); + IQueryable GetUserAccess(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ISentinelRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ISentinelRepository.cs new file mode 100644 index 0000000..cdc5484 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ISentinelRepository.cs @@ -0,0 +1,10 @@ +using e_suite.Database.Core.Tables.Sentinel; + +namespace e_suite.API.Common.repository; + +public interface ISentinelRepository +{ + Task AddFailedAccessAttempt(FailedAccessAttempt failedLoginAttempt, CancellationToken cancellationToken); + Task GetAccessAttemptsSince(string ipAddress, DateTimeOffset earliestAttemptTime, CancellationToken cancellationToken); + Task DeleteAccessAttemptsBefore(DateTimeOffset earliestAttemptTime); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ISequenceManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ISequenceManagerRepository.cs new file mode 100644 index 0000000..87a7e17 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ISequenceManagerRepository.cs @@ -0,0 +1,15 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Sequences; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface ISequenceManagerRepository : IRepository +{ + Task AddSequence(AuditUserDetails auditUserDetails, Sequence sequence, CancellationToken cancellationToken); + Task EditSequence(AuditUserDetails auditUserDetails, Sequence sequence, CancellationToken cancellationToken); + Task GetSequenceById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetSequenceByName(string Name, CancellationToken cancellationToken); + IQueryable GetSequenceList(); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ISiteManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ISiteManagerRepository.cs new file mode 100644 index 0000000..72f156c --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ISiteManagerRepository.cs @@ -0,0 +1,16 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface ISiteManagerRepository : IRepository +{ + IQueryable GetSites(); + Task GetSite(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetSite(long sigmaId, CancellationToken cancellationToken); + Task EditSite(AuditUserDetails auditUserDetails, Site editedSite, CancellationToken cancellationToken); + Task CreateSite(AuditUserDetails auditUserDetails, Site newSite, CancellationToken cancellationToken); + Task CreateSite(AuditUserDetails auditUserDetails, IEnumerable newSites, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ISpecificationManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ISpecificationManagerRepository.cs new file mode 100644 index 0000000..c5279dd --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ISpecificationManagerRepository.cs @@ -0,0 +1,18 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface ISpecificationManagerRepository : IRepository +{ + IQueryable GetSpecifications(); + IQueryable GetSpecificationsFromForms(IEnumerable formIds); + Task GetSpecification(GeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task CreateSpecification(AuditUserDetails auditUserDetails, Specification newSpecification, CancellationToken cancellationToken); + Task CreateSpecification(AuditUserDetails auditUserDetails, IEnumerable newSpecification, CancellationToken cancellationToken); + + Task EditSpecification(AuditUserDetails auditUserDetails, Specification specification, CancellationToken cancellationToken); + Task EditSpecification(AuditUserDetails auditUserDetails, IEnumerable specifications, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/ISsoManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/ISsoManagerRepository.cs new file mode 100644 index 0000000..4943df8 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/ISsoManagerRepository.cs @@ -0,0 +1,14 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface ISsoManagerRepository : IRepository +{ + IQueryable GetSsoProviders(); + Task GetSsoProviderAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task CreateNewSsoProviderAsync(AuditUserDetails auditUserDetails, SsoProvider newSsoProvider, CancellationToken cancellationToken); + Task EditNewSsoProviderAsync(AuditUserDetails auditUserDetails, SsoProvider ssoProvider, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API.Common/e-suite.API.Common/repository/IUserManagerRepository.cs b/e-suite.API.Common/e-suite.API.Common/repository/IUserManagerRepository.cs new file mode 100644 index 0000000..ca1b7c4 --- /dev/null +++ b/e-suite.API.Common/e-suite.API.Common/repository/IUserManagerRepository.cs @@ -0,0 +1,33 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; + +namespace e_suite.API.Common.repository; + +public interface IUserManagerRepository : IRepository +{ + Task GetUserByEmail(string loginEmail, CancellationToken cancellationToken); + Task GetUserSsoId(long ssoId, string ssoUserId, CancellationToken cancellationToken); + Task GetUserByDomainSsoId(long domainSsoId, string ssoUserId, CancellationToken cancellationToken); + + Task AddEmailUserAction(AuditUserDetails auditUserDetails, EmailUserAction emailConfirmation, + CancellationToken cancellationToken); + Task AddUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken); + Task EditUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken); + Task GetEmailUserAction(Guid token, CancellationToken cancellationToken); + Task GetCurrentEmailUserAction(long userId, EmailUserActionType emailUserActionType, CancellationToken cancellationToken); + Task DeleteEmailUserAction(AuditUserDetails auditUserDetails, EmailUserAction emailUserAction, CancellationToken cancellationToken); + IQueryable GetUsers(); + Task GetUserById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken); + Task GetSsoProviderById(long id, CancellationToken cancellationToken); + IQueryable GetSsoProviders(); + Task SaveSingleUseGuidForUser(SingleUseGuid singleUseGuid, CancellationToken cancellationToken); + Task GetUserBySingleUseGuid(Guid guid, CancellationToken cancellationToken); + Task DeleteSingleUseGuid(Guid guid, CancellationToken cancellationToken); + Task GetDomainById(GeneralIdRef userRegistrationDomainId, CancellationToken cancellationToken); + Task DeleteExpiredEmailUserActions(); + Task DeleteExpiredSingleUseGuids(); +} \ No newline at end of file diff --git a/e-suite.API.Common/nuget.config b/e-suite.API.Common/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.API.Common/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.API/.dockerignore b/e-suite.API/.dockerignore new file mode 100644 index 0000000..bdca33b --- /dev/null +++ b/e-suite.API/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/e-suite.API/.gitattributes b/e-suite.API/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.API/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.API/.gitignore b/e-suite.API/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.API/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.API/.runsettings b/e-suite.API/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.API/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.API/README.md b/e-suite.API/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.API/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.API/StartE-Suite.cmd b/e-suite.API/StartE-Suite.cmd new file mode 100644 index 0000000..6eb3238 --- /dev/null +++ b/e-suite.API/StartE-Suite.cmd @@ -0,0 +1,27 @@ +@echo off +echo running in %~dp0 + +set DOTNET_ENVIRONMENT=Development + + + +cd %~dp0\e-suite.Database.Migrator\bin\Debug\net6.0 +e-suite.Database.Migrator.exe + +if %ERRORLEVEL% == 0 goto startapi + +echo ERROR MIGRATING DATABASE, PLEASE FIX THIS NOW +pause +goto end + +:startapi +echo starting api + +cd %~dp0\eSuite.API\bin\Debug\net6.0 +start eSuite.API.exe + +start "" https://localhost:7066/swagger/index.html + +goto end + +:end \ No newline at end of file diff --git a/e-suite.API/azure-pipelines.yml b/e-suite.API/azure-pipelines.yml new file mode 100644 index 0000000..65f544b --- /dev/null +++ b/e-suite.API/azure-pipelines.yml @@ -0,0 +1,142 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(postfix)$(branchName) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: ubuntu-latest # ubuntu-latest - set to windows-latest or another Windows vmImage for Windows builds + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + containerRegistry: esuite.azurecr.io + DOCKER_BUILDKIT: 1 + + apiImageName: 'e-suite.api' + migratorImageName: 'e-suite.database.migrator' + + apiPublishPath: $(Build.Repository.LocalPath)/build/eSuite.API + migratorPublishPath: $(Build.ArtifactStagingDirectory)/build/e-suite.Database.Migrator + + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + branchName: '' + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}: + branchName: $[ replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-' ) ] + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}: + branchName: $[ replace(replace(variables['System.PullRequest.TargetBranch'], 'refs/heads/', ''), '/', '-' ) ] + + ${{ if eq(variables['branchName'], '') }}: + postfix: '' + ${{ else }}: + postfix: '-' + +steps: +- task: UseDotNet@2 + displayName: 'Set .net core version' + inputs: + version: '9.0.x' + +- task: DotNetCoreCLI@2 + displayName: 'Nuget Restore' + inputs: + command: 'restore' + feedsToUse: config + projects: '**/*.csproj' + nugetConfigPath: nuget.config + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--configuration $(buildConfiguration)' + displayName: 'dotnet build $(buildConfiguration)' + +- task: DotNetCoreCLI@2 + displayName: 'Run Tests' + inputs: + command: test + projects: '**/*Tests/*.csproj' + arguments: '--configuration $(buildConfiguration) --collect "Code coverage" --settings .runsettings' + +- task: DotNetCoreCLI@2 + displayName: 'Publish e-suite.API' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: publish + projects: 'eSuite.API/eSuite.API.csproj' + publishWebProjects: false + arguments: -c $(BuildConfiguration) -o build + zipAfterPublish: false + +- task: Docker@2 + displayName: Build e-suite API Image + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: build + repository: $(apiImageName) + buildContext: $(apiPublishPath) + Dockerfile: $(apiPublishPath)/Dockerfile.Azure + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) + +- task: DotNetCoreCLI@2 + displayName: 'Publish e-suite.Database.Migrator' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: publish + projects: 'e-suite.Database.Migrator/e-suite.Database.Migrator.csproj' + publishWebProjects: false + arguments: '--configuration $(BuildConfiguration) --output $(migratorPublishPath)' + zipAfterPublish: false + +- powershell: | + Write-Host "Show all folder content" + Get-ChildItem -Path $(migratorPublishPath)\*.* -Recurse -Force | % { $_.FullName } + errorActionPreference: continue + displayName: 'PowerShell Script List folder structure' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + continueOnError: true + +- task: Docker@2 + displayName: Build e-suite Database Migrator image + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: build + repository: $(migratorImageName) + buildContext: $(migratorPublishPath)/e-suite.Database.Migrator + Dockerfile: $(migratorPublishPath)/e-suite.Database.Migrator/Dockerfile.Azure + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) + +- task: Docker@2 + displayName: Push e-suite API Image + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: push + repository: $(apiImageName) + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) + +- task: Docker@2 + displayName: Push e-suite Database Migrator image + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: push + repository: $(migratorImageName) + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/.dockerignore b/e-suite.API/e-suite.Database.Migrator/.dockerignore new file mode 100644 index 0000000..bdca33b --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Dockerfile b/e-suite.API/e-suite.Database.Migrator/Dockerfile new file mode 100644 index 0000000..150a431 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Dockerfile @@ -0,0 +1,21 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/runtime:9.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src +COPY ["nuget.config", "."] +COPY ["e-suite.Database.Migrator/e-suite.Database.Migrator.csproj", "e-suite.Database.Migrator/"] +RUN dotnet restore "e-suite.Database.Migrator/e-suite.Database.Migrator.csproj" +COPY . . +WORKDIR "/src/e-suite.Database.Migrator" +RUN dotnet build "e-suite.Database.Migrator.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "e-suite.Database.Migrator.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "e-suite.Database.Migrator.dll"] \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Dockerfile.Azure b/e-suite.API/e-suite.Database.Migrator/Dockerfile.Azure new file mode 100644 index 0000000..dd29230 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Dockerfile.Azure @@ -0,0 +1,7 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 as base +ENV DOTNET_ENVIRONMENT=Development +WORKDIR /app +COPY . . +ENTRYPOINT ["dotnet", "e-suite.Database.Migrator.dll"] \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Migrations/ScriptParser.cs b/e-suite.API/e-suite.Database.Migrator/Migrations/ScriptParser.cs new file mode 100644 index 0000000..f63bd48 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Migrations/ScriptParser.cs @@ -0,0 +1,49 @@ +namespace e_suite.Database.Migrator.Migrations; + +public class ScriptParser +{ + public static string GetScriptText(ScriptType scriptType, string databaseName) + { + var scriptFileName = Path.Combine(AppContext.BaseDirectory, "Scripts", GetScriptFileName(scriptType)); + + if (!File.Exists(scriptFileName)) + return string.Empty; + + var fileContents = File.ReadAllText(scriptFileName).Trim(); + + return ParseScript(fileContents, databaseName); + } + + private static string ParseScript(string fileContents, string databaseName) + { + if (string.IsNullOrWhiteSpace(fileContents)) + return fileContents; + + var parameterDictionary = new Dictionary + { + { "SQL_APPLICATION_USER", Environment.GetEnvironmentVariable("SQL_APPLICATION_USER") ?? $"{databaseName}ApplicationUser" }, + { "SQL_APPLICATION_PASSWORD", Environment.GetEnvironmentVariable("SQL_APPLICATION_PASSWORD") ?? "Plz change me on live, thank you" }, + { "SQL_DATABASE", Environment.GetEnvironmentVariable("SQL_DATABASE") ?? databaseName }, + { "SQL_SERVER", Environment.GetEnvironmentVariable("SQL_SERVER") ?? string.Empty }, + }; + + var parsedContents = fileContents; + foreach (KeyValuePair keyValuePair in parameterDictionary) + { + parsedContents = parsedContents.Replace("$(" + keyValuePair.Key + ")", keyValuePair.Value); + } + + return parsedContents; + } + + private static string GetScriptFileName(ScriptType scriptType) + { + return scriptType switch + { + ScriptType.resetDatabase => "ResetDatabaseScript.sql", + ScriptType.preMigration => "PreMigrationScript.sql", + ScriptType.postMigration => "PostMigrationScript.sql", + _ => throw new NotImplementedException() + }; + } +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Migrations/ScriptType.cs b/e-suite.API/e-suite.Database.Migrator/Migrations/ScriptType.cs new file mode 100644 index 0000000..589af31 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Migrations/ScriptType.cs @@ -0,0 +1,8 @@ +namespace e_suite.Database.Migrator.Migrations; + +public enum ScriptType +{ + resetDatabase, + preMigration, + postMigration +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Program.cs b/e-suite.API/e-suite.Database.Migrator/Program.cs new file mode 100644 index 0000000..00dc6ea --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Program.cs @@ -0,0 +1,39 @@ +// See https://aka.ms/new-console-template for more information + +using e_suite.API.Common.extensions; +using e_suite.Database.Migrator.Migrations; +using e_suite.Database.Migrator.SqlWrapper; +using e_suite.Database.SqlServer; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; + +Console.WriteLine($"Environment: {Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}"); + +var configuration = ESuiteDatabaseExtension.BuildConfiguration(); + +var databaseName = configuration.GetConfigValue("SQL_DATABASE", "database:databaseName", "esuite")!; +var resetDatabaseName = configuration.GetConfigValue("RESET_DATABASE", "database:resetDatabase", false); + +var connectionString = ESuiteDatabaseExtension.BuildConnectionString(configuration); + +if (resetDatabaseName) + PrePostScriptRunner.RunScripts(connectionString, databaseName, ScriptType.resetDatabase); + +PrePostScriptRunner.RunScripts(connectionString, databaseName, ScriptType.preMigration); + +Console.WriteLine("Migrating database"); +try +{ + var database = await ESuiteDatabaseExtension.CreateDatabase(new UtcClock()); + database.Database.Migrate(); + + Console.WriteLine("Database migration completed"); +} +catch (Exception e) +{ + Console.WriteLine("Database migration failed"); + Console.WriteLine(e); + throw; +} + +PrePostScriptRunner.RunScripts(connectionString, databaseName, ScriptType.postMigration); \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Properties/launchSettings.json b/e-suite.API/e-suite.Database.Migrator/Properties/launchSettings.json new file mode 100644 index 0000000..d8f23bc --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "e-suite.Database.Migrator": { + "commandName": "Project", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker" + } + } +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Scripts/PostMigrationScript.sql b/e-suite.API/e-suite.Database.Migrator/Scripts/PostMigrationScript.sql new file mode 100644 index 0000000..71dc1cd --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Scripts/PostMigrationScript.sql @@ -0,0 +1 @@ +ALTER USER [$(SQL_APPLICATION_USER)] WITH PASSWORD=N'$(SQL_APPLICATION_PASSWORD)', DEFAULT_SCHEMA=[dbo] \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Scripts/PreMigrationScript.sql b/e-suite.API/e-suite.Database.Migrator/Scripts/PreMigrationScript.sql new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Scripts/PreMigrationScript.sql @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/Scripts/ResetDatabaseScript.sql b/e-suite.API/e-suite.Database.Migrator/Scripts/ResetDatabaseScript.sql new file mode 100644 index 0000000..435428f --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/Scripts/ResetDatabaseScript.sql @@ -0,0 +1,52 @@ +DECLARE @sql NVARCHAR(max)='' + +--dropping views +SET @sql = ''; + +SELECT @sql += ' Drop view ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(v.NAME) + '; ' +FROM sys.views v +JOIN sys.schemas s + ON v.[schema_id] = s.[schema_id] +WHERE v.is_ms_shipped = 0 + +EXEC sp_executesql @sql + +--dropping foreign keys +SET @sql = ''; +SELECT @sql += 'Alter table ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' drop constraint ' + QUOTENAME(fk.name) +'; ' +FROM sys.foreign_keys AS fk +JOIN sys.tables AS t + ON t.object_id = fk.parent_object_id +JOIN sys.schemas AS s + ON s.schema_id = t.schema_id + +Exec sp_executesql @sql + +--dropping prinary and unique keys +SET @sql = ''; +SELECT @sql += 'Alter table ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' drop constraint ' + QUOTENAME(kc.name) +'; ' +FROM sys.key_constraints AS kc +JOIN sys.tables AS t + ON t.object_id = kc.parent_object_id +JOIN sys.schemas AS s + ON s.schema_id = t.schema_id + +EXEC sp_executesql @sql + +--dropping tables +SET @sql = ''; +SELECT @sql += ' Drop table ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + '; ' +FROM sys.tables AS t +JOIN sys.schemas AS s + ON t.[schema_id] = s.[schema_id] +WHERE t.type = 'U' + +EXEC sp_executesql @sql + +--removing application user +SET @sql = ''; +SELECT @sql += 'drop user ' + QUOTENAME(p.name) +FROM sys.database_principals AS p +WHERE p.authentication_type = 2 + +EXEC sp_executesql @sql diff --git a/e-suite.API/e-suite.Database.Migrator/SqlWrapper/ISqlWrapper.cs b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/ISqlWrapper.cs new file mode 100644 index 0000000..a7d276d --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/ISqlWrapper.cs @@ -0,0 +1,85 @@ +using System.Data; +using System.Xml; +using System.Xml.Linq; + +namespace e_suite.Database.Migrator.SqlWrapper; + +public interface ISqlWrapper : IDisposable +{ + /// + /// Name of the stored procedure to call. + /// Note: can use either CommandName or the CommandText, but not both at the same time. + /// + string CommandName { get; set; } + + /// + /// Adhoc SQL text. + /// Note: can use either CommandName or the CommandText, but not both at the same time. + /// + string CommandText { get; set; } + + void AddParameter(string name, SqlDbType type, object value); + + /// + /// Adds a new parameter to the stored procedure + /// + /// name of the parameter. For example @test the @ symbol is optional + /// database type of the parameter + /// Specifies if this is an input or output parameter + /// actual value for the parameter + void AddParameter(string name, SqlDbType type, ParameterDirection direction, object value); + + /// + /// Retrieves the current value of a parameter + /// + /// name of the parameter that you need the value for + /// either the value of the named parameter, or null if it does not exist + object? GetParamValue(string name); + + /// + /// Removes all parameters from the internal parameter list. + /// + void Clear(); + + + /// + /// Execute the stored procedure without the expectation of any result sets being returned. + /// note: output parameters will be set when the method completes. + /// + void Execute(); + + /// + /// Retrieves the procedures return value + /// + /// the return value from the procedure call + object? GetReturnValue(); + + /// + /// Execute stored procedure with return an XML reader. + /// + /// + XmlReader ExecuteXmlReader(); + + /// + /// Execute the stored procedure with the result returned as an XmlDocument + /// + /// XML document containing the result of the stored procedure call + XmlDocument ExecuteXmlDocument(); + + /// + /// Execute the stored procedure with the result returned as an XDcoument + /// + /// + XDocument ExecuteXDocument(); + + IDataReader ExecuteReader(); + + + bool IsDisposed { get; } + int ParamCount { get; } + + /// + /// Timeout for sql commands. Default is 30 seconds. 0 means no limit. + /// + int Timeout { get; set; } +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/SqlWrapper/PrePostScriptRunner.cs b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/PrePostScriptRunner.cs new file mode 100644 index 0000000..a18f27e --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/PrePostScriptRunner.cs @@ -0,0 +1,40 @@ +using e_suite.Database.Migrator.Migrations; + +namespace e_suite.Database.Migrator.SqlWrapper; + +public static class PrePostScriptRunner +{ + public static void RunScripts(string connectionString, string databaseName, ScriptType scriptType) + { + Console.WriteLine($"Running {scriptType} scripts"); + try + { + var parsedScript = ScriptParser.GetScriptText(scriptType, databaseName); + if (parsedScript != string.Empty) + { + try + { + using var sqlWrapper = new SqlWrapper(connectionString); + sqlWrapper.CommandText = parsedScript; + sqlWrapper.Execute(); + Console.WriteLine($"{scriptType} scripts completed"); + } + catch (Exception e) + { + Console.WriteLine($"{scriptType} scripts skipped - Unable to connect to sql server"); + Console.WriteLine(e); + } + } + else + { + Console.WriteLine($"{scriptType} scripts skipped - no content"); + } + } + catch (Exception e) + { + Console.WriteLine($"{scriptType} scripts failed"); + Console.WriteLine(e); + throw; + } + } +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/SqlWrapper/SecureSqlParameterExtensions.cs b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/SecureSqlParameterExtensions.cs new file mode 100644 index 0000000..9dac8bc --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/SecureSqlParameterExtensions.cs @@ -0,0 +1,171 @@ +using System.Data; +using System.Runtime.InteropServices; +using System.Security; +using Microsoft.Data.SqlClient; + +namespace e_suite.Database.Migrator.SqlWrapper; + +public static class SecureSqlParameterExtensions +{ + [DllImport("kernel32.dll", EntryPoint = "CopyMemory")] + private static extern void CopyMemory(IntPtr dest, IntPtr src, IntPtr count); + [DllImport("kernel32.dll", EntryPoint = "RtlZeroMemory")] + private static extern void ZeroMemory(IntPtr ptr, IntPtr count); + + /// + /// You must dispose the return value as soon as SqlCommand.Execute* is called. + /// + public static IDisposable AddSecure(this SqlParameterCollection collection, string name, SecureString secureString) + { + var value = new SecureStringParameterValue(secureString); + collection.Add(name, SqlDbType.NVarChar).Value = value; + return value; + } + + private sealed class SecureStringParameterValue : IConvertible, IDisposable + { + private readonly SecureString? _secureString; + private int _length; + private string? _insecureManagedCopy; + private GCHandle _insecureManagedCopyGcHandle; + + public SecureStringParameterValue(SecureString secureString) + { + _secureString = secureString; + } + + #region IConvertible + + public TypeCode GetTypeCode() + { + return TypeCode.String; + } + + public string ToString(IFormatProvider? provider) + { + if (_insecureManagedCopy != null) return _insecureManagedCopy; + if (_secureString == null || _secureString.Length == 0) return string.Empty; + + // We waited till the last possible minute. + + // Here's the plan: + // 1. Create a new managed string initialized to zero + // 2. Pin the managed string so the GC leaves it alone + // 3. Copy the contents of the SecureString into the managed string + // 4. Use the string as a SqlParameter + // 5. Zero the managed string after Execute* is called and free the GC handle + + _length = _secureString.Length; + _insecureManagedCopy = new string('\0', _length); + _insecureManagedCopyGcHandle = GCHandle.Alloc(_insecureManagedCopy, GCHandleType.Pinned); // Do not allow the GC to move this around and leave copies behind + + try + { + // This is the only way to read the contents, sadly. + // SecureStringToBSTR picks where to put it, so we have to copy it from there and zerofree the unmanaged copy as fast as possible. + IntPtr insecureUnmanagedCopy = Marshal.SecureStringToBSTR(_secureString); + try + { + CopyMemory(_insecureManagedCopyGcHandle.AddrOfPinnedObject(), insecureUnmanagedCopy, (IntPtr)(_length * 2)); + } + finally + { + if (insecureUnmanagedCopy != IntPtr.Zero) Marshal.ZeroFreeBSTR(insecureUnmanagedCopy); + } + + // Now the string managed string has the contents in the clear. + return _insecureManagedCopy; + } + catch + { + Dispose(); + throw; + } + } + + public void Dispose() + { + if (_insecureManagedCopy == null) return; + _insecureManagedCopy = null; + ZeroMemory(_insecureManagedCopyGcHandle.AddrOfPinnedObject(), (IntPtr)(_length * 2)); + _insecureManagedCopyGcHandle.Free(); + } + + public bool ToBoolean(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public char ToChar(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public sbyte ToSByte(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public byte ToByte(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public short ToInt16(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public ushort ToUInt16(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public int ToInt32(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public uint ToUInt32(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public long ToInt64(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public ulong ToUInt64(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public float ToSingle(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public double ToDouble(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public decimal ToDecimal(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public DateTime ToDateTime(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public object ToType(Type conversionType, IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + #endregion + } +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/SqlWrapper/SqlWrapper.cs b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/SqlWrapper.cs new file mode 100644 index 0000000..0ad1068 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/SqlWrapper/SqlWrapper.cs @@ -0,0 +1,313 @@ +using Microsoft.Data.SqlClient; +using System.Data; +using System.Security; +using System.Xml.Linq; +using System.Xml; + +namespace e_suite.Database.Migrator.SqlWrapper; + +public class SqlWrapper : ISqlWrapper +{ + /// + /// contains the details of parameter including the value. Settings the value to null or DBNull.Value will result in a DBNull.Value being passed with the stored procedure call. + /// + private struct SqlParam + { + public string Name; + public SqlDbType Type; + public ParameterDirection Direction; + public object Value; + } + + private const string ReturnValueParamName = "_ReturnValue"; + private readonly IDbConnection _sqlConn; + private readonly List _sqlParams; + private string _commandName = string.Empty; + private string _commandText = string.Empty; + + public string CommandName + { + get => _commandName; + set + { + if (_commandName != value) + { + _commandName = value; + if (!string.IsNullOrEmpty(_commandText)) + { + _commandText = string.Empty; + } + } + } + } + + public string CommandText + { + get => _commandText; + set + { + if (_commandText != value) + { + _commandText = value; + if (!string.IsNullOrEmpty(_commandName)) + { + _commandName = string.Empty; + } + } + } + } + + /// + /// Creates an instance of the SqlCommand. Wraps setting everything needed to make a stored procedure call based on the parameters supplied. + /// + /// Prepared SqlCommand object ready for execution. + /// FxCop warning has been deliberately suppressed as the CommandText is only allowed to be a stored procedure name. + /// This is ensured by the hard coding of the CommandType. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] + private SqlCommand PrepareSqlCommand() + { + SqlCommand sqlCommand; + SqlCommand? tempSqlCommand = null; + + try + { + tempSqlCommand = new SqlCommand + { + CommandTimeout = Timeout, + Connection = _sqlConn as SqlConnection + }; + + if (!string.IsNullOrEmpty(CommandName)) + { + tempSqlCommand.CommandType = CommandType.StoredProcedure; + tempSqlCommand.CommandText = CommandName; + } + else if (!string.IsNullOrEmpty(CommandText)) + { + tempSqlCommand.CommandType = CommandType.Text; + tempSqlCommand.CommandText = CommandText; + } + + foreach (var sqlParam in _sqlParams) + { + if (sqlParam.Value is SecureString sqlParamValue) + { + tempSqlCommand.Parameters.AddSecure(sqlParam.Name, sqlParamValue); + } + else + { + var sqlParameter = tempSqlCommand.Parameters.Add(sqlParam.Name, sqlParam.Type); + + if (sqlParam.Type == SqlDbType.VarChar) + { + sqlParameter.Size = -1; + } + sqlParameter.Direction = sqlParam.Direction; + sqlParameter.Value = sqlParam.Value; + } + } + + sqlCommand = tempSqlCommand; + } + catch + { + tempSqlCommand?.Dispose(); + throw; + } + + return sqlCommand; + } + + /// + /// retrieves the output parameters putting each into their respective SqlParam contained in the sqlParams list. + /// + /// the SqlCommand object after execution so that the output parameters may be retrieved. + private void RetrieveOutputParams(SqlCommand sqlCommand) + { + ParameterDirection[] outParamDirections = { ParameterDirection.InputOutput, ParameterDirection.Output, ParameterDirection.ReturnValue }; + + foreach (SqlParameter sqlParameter in sqlCommand.Parameters) + { + if (outParamDirections.Contains(sqlParameter.Direction)) + { + for (int i = 0; i < _sqlParams.Count; i++) + { + SqlParam sqlParam = _sqlParams[i]; + + if (sqlParam.Name == sqlParameter.ParameterName) + { + sqlParam.Value = sqlParameter.Value; + _sqlParams[i] = sqlParam; //will this be needed? + break; + } + } + } + } + } + + /// + /// class constructor. this will create and immediately open the database connection. + /// + public SqlWrapper(string connectionString) //constructor + { + _sqlConn = new SqlConnection(connectionString); + _sqlConn.Open(); + _sqlParams = new List(); + } + + public SqlWrapper(IDbConnection sqlConnection) //constructor + { + _sqlConn = sqlConnection; + _sqlConn.Open(); + _sqlParams = new List(); + } + + /// + /// Overrideable Dispose method. This will be called when the object is destroyed, either by ending a uses clause or by the garbage collector. + /// + /// states that this was called by the garbage collector + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) + { + _sqlConn.Close(); + } + } + IsDisposed = true; + } + + /// + /// object destructor, will call the overridable Dispose method. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public bool IsDisposed { get; private set; } + + /// + /// Removes all parameters from the internal parameter list. + /// + public void Clear() + { + _sqlParams.Clear(); + } + + public int ParamCount => _sqlParams.Count; + + public int Timeout { get; set; } = 30; + + public void AddParameter(string name, SqlDbType type, object value) + { + AddParameter(name, type, ParameterDirection.Input, value); + } + + /// + /// Adds a new parameter to the stored procedure + /// + /// name of the parameter. For example @test the @ symbol is optional + /// database type of the parameter + /// Specifies if this is an input or output parameter + /// actual value for the parameter + public void AddParameter(string name, SqlDbType type, ParameterDirection direction, object? value) + { + if (value == null) + { + value = DBNull.Value; + } + + SqlParam sqlParam = new SqlParam + { + Name = name, + Type = type, + Direction = direction, + Value = value + }; + + _sqlParams.Add(sqlParam); + } + + /// + /// Retrieves the current value of a parameter + /// + /// name of the parameter that you need the value for + /// either the value of the named parameter, or null if it does not exist + public object? GetParamValue(string name) + { + foreach (var sqlParam in _sqlParams) + { + if (sqlParam.Name == name) + { + return sqlParam.Value; + } + } + return null; + } + + /// + /// Retrieves the procedures return value + /// + /// the return value from the procedure call + public object? GetReturnValue() + { + return GetParamValue(ReturnValueParamName); + } + + /// + /// Execute the stored procedure without the expectation of any result sets being returned. + /// note: output parameters will be set when the method completes. + /// + public void Execute() + { + AddParameter(ReturnValueParamName, SqlDbType.Int, ParameterDirection.ReturnValue, null); + using (SqlCommand sqlCommand = PrepareSqlCommand()) + { + sqlCommand.ExecuteNonQuery(); + RetrieveOutputParams(sqlCommand); + } + } + + + public XmlReader ExecuteXmlReader() + { + using (SqlCommand sqlCommand = PrepareSqlCommand()) + { + return sqlCommand.ExecuteXmlReader(); + } + } + + /// + /// Execute the stored procedure with the expection of an XML Stream result set. + /// + /// XML document containing the result of the stored procedure call + public XmlDocument ExecuteXmlDocument() + { + using (XmlReader xReader = ExecuteXmlReader()) + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(xReader); + return xmlDocument; + } + } + + public XDocument ExecuteXDocument() + { + using (XmlReader xReader = ExecuteXmlReader()) + { + XDocument xmlDocument = XDocument.Load(xReader); + return xmlDocument; + } + } + + public IDataReader ExecuteReader() + { + using (SqlCommand sqlCommand = PrepareSqlCommand()) + { + return sqlCommand.ExecuteReader(); + } + } +} \ No newline at end of file diff --git a/e-suite.API/e-suite.Database.Migrator/appsettings.Development.json b/e-suite.API/e-suite.Database.Migrator/appsettings.Development.json new file mode 100644 index 0000000..6024f10 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/appsettings.Development.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "database": { + "server": "(local)", + "databaseName": "esuite", + "encrypt": true, + "trustServerCertificate": true + } +} diff --git a/e-suite.API/e-suite.Database.Migrator/appsettings.Production.json b/e-suite.API/e-suite.Database.Migrator/appsettings.Production.json new file mode 100644 index 0000000..6024f10 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/appsettings.Production.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "database": { + "server": "(local)", + "databaseName": "esuite", + "encrypt": true, + "trustServerCertificate": true + } +} diff --git a/e-suite.API/e-suite.Database.Migrator/appsettings.json b/e-suite.API/e-suite.Database.Migrator/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/e-suite.API/e-suite.Database.Migrator/e-suite.Database.Migrator.csproj b/e-suite.API/e-suite.Database.Migrator/e-suite.Database.Migrator.csproj new file mode 100644 index 0000000..0e72dee --- /dev/null +++ b/e-suite.API/e-suite.Database.Migrator/e-suite.Database.Migrator.csproj @@ -0,0 +1,64 @@ + + + + Exe + net10.0 + e_suite.Database.Migrator + enable + enable + Linux + + + + + + + + + + + + + + Always + true + PreserveNewest + + + Always + true + PreserveNewest + + + Always + true + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/AccountControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/AccountControllerTestBase.cs new file mode 100644 index 0000000..5c40e72 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/AccountControllerTestBase.cs @@ -0,0 +1,49 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.Service.Sentinel; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using eSuite.API.SingleSignOn; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +public abstract class AccountControllerTestBase : TestBase +{ + protected AccountController _accountController = null!; + protected Mock _userManagerMock = null!; + protected Mock _sentinelMock = null!; + protected Mock _singleSignOnMock = null!; + protected Mock _cookieManagerMock = null!; + + public override async Task Setup() + { + await base.Setup(); + + _userManagerMock = new Mock(); + _sentinelMock = new Mock(); + _singleSignOnMock = new Mock(); + _cookieManagerMock = new Mock(); + + _accountController = new AccountController(_userManagerMock.Object,_sentinelMock.Object, _singleSignOnMock.Object, _cookieManagerMock.Object); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _accountController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } + +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/AuthUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/AuthUnitTests.cs new file mode 100644 index 0000000..aef9f6b --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/AuthUnitTests.cs @@ -0,0 +1,170 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.API.SingleSignOn; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class AuthUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task Auth_WhenCalledInNormalSsoProcess_LogsInCreatesSessionCookiesAndRedirectsToRoot() + { + //Arrange + var ssoId = 1; + var code = "code"; + var scope = "scope"; + var authUser = "authUser"; + var prompt = "prompt"; + + var ssoUserId = "ssoUserId123456"; + _singleSignOnMock.Setup(x => x.ExchangeAuthorisationToken(ssoId, code, It.IsAny())) + .ReturnsAsync(() => ssoUserId); + + var loginResponse = new LoginResponse + { + Result = LoginResult.Success, + Token = "Json Web Toke goes here" + }; + + _userManagerMock.Setup(x => x.LoginSso(ssoId, ssoUserId, It.IsAny())) + .ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.Auth(ssoId, code, scope, authUser, prompt, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/")); + + _cookieManagerMock.Verify(x => x.CreateSessionCookie(It.IsAny(), loginResponse), Times.Once); + _cookieManagerMock.Verify(x => x.CreateSsoIdCookie(It.IsAny(), ssoId), Times.Once); + _sentinelMock.Verify(x => x.LogBadRequest(_accountController, It.IsAny()), Times.Never); + } + + [Test] + public async Task Auth_WhenLoginFails_DoesNotLoginRedirectsToRootAndLogsBadRequest() + { + //Arrange + var ssoId = 1; + var code = "code"; + var scope = "scope"; + var authUser = "authUser"; + var prompt = "prompt"; + + var ssoUserId = "ssoUserId123456"; + _singleSignOnMock.Setup(x => x.ExchangeAuthorisationToken(ssoId, code, It.IsAny())) + .ReturnsAsync(() => ssoUserId); + + var loginResponse = new LoginResponse + { + Result = LoginResult.Failed + }; + + _userManagerMock.Setup(x => x.LoginSso(ssoId, ssoUserId, It.IsAny())) + .ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.Auth(ssoId, code, scope, authUser, prompt, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/")); + + _cookieManagerMock.Verify(x => x.CreateSessionCookie(It.IsAny(), loginResponse), Times.Never); + _cookieManagerMock.Verify(x => x.CreateSsoIdCookie(It.IsAny(), ssoId), Times.Never); + _sentinelMock.Verify( x => x.LogBadRequest(_accountController, It.IsAny()), Times.Once); + } + + [TestCase(LoginResult.EmailNotConfirmed)] + [TestCase(LoginResult.TwoFactorAuthenticationRemovalRequested)] + [TestCase(LoginResult.TwoFactorAuthenticationCodeRequired)] + [TestCase(LoginResult.TwoFactorAuthenticationCodeIncorrect)] + public async Task Auth_WhenLoginCannotComplete_DoesNotLoginAndRedirectsToRoot(LoginResult loginResult) + { + //Arrange + var ssoId = 1; + var code = "code"; + var scope = "scope"; + var authUser = "authUser"; + var prompt = "prompt"; + + var ssoUserId = "ssoUserId123456"; + _singleSignOnMock.Setup(x => x.ExchangeAuthorisationToken(ssoId, code, It.IsAny())) + .ReturnsAsync(() => ssoUserId); + + var loginResponse = new LoginResponse + { + Result = loginResult + }; + + _userManagerMock.Setup(x => x.LoginSso(ssoId, ssoUserId, It.IsAny())) + .ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.Auth(ssoId, code, scope, authUser, prompt, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/")); + + _cookieManagerMock.Verify(x => x.CreateSessionCookie(It.IsAny(), loginResponse), Times.Never); + _cookieManagerMock.Verify(x => x.CreateSsoIdCookie(It.IsAny(), ssoId), Times.Never); + _sentinelMock.Verify(x => x.LogBadRequest(_accountController, It.IsAny()), Times.Never); + } + + [Test] + public async Task Auth_WhenProfileLinkCookieDetected_DeletesSingleUserCookieLinksSsoUserIdToAccountAndRedirectsToProfileEditPage() + { + //Arrange + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var ssoId = 1; + var code = "code"; + var scope = "scope"; + var authUser = "authUser"; + var prompt = "prompt"; + + var ssoUserId = "ssoUserId123456"; + _singleSignOnMock.Setup(x => x.ExchangeAuthorisationToken(ssoId, code, It.IsAny())) + .ReturnsAsync(() => ssoUserId); + + var user = new User(); + + _cookieManagerMock + .Setup(x => x.GetUserIdFromLinkCookie(It.IsAny(), It.IsAny())) + .ReturnsAsync(() => new CookieLink + { + User = user, LinkType = LinkType.Profile + + }); + + //Act + var response = await _accountController.Auth(ssoId, code, scope, authUser, prompt, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/profile")); + + _cookieManagerMock.Verify(x => x.DeleteLinkCookie(It.IsAny()), Times.Once); + _userManagerMock.Verify( x => x.LinkSsoProfileToUser(It.IsAny(), It.IsAny(), ssoId, ssoUserId, It.IsAny(),It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LoginGetUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LoginGetUnitTests.cs new file mode 100644 index 0000000..f8c2f12 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LoginGetUnitTests.cs @@ -0,0 +1,93 @@ +using e_suite.API.Common.models; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class LoginGetUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LoginGet_WhenLoginNotPresent_ReturnsLoginViewWithEmptyModel() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + Login? login = null; + + //Act + var response = await _accountController.LoginGet(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.Not.Null); + Assert.That(actualLogin?.Email, Is.EqualTo(string.Empty)); + Assert.That(actualLogin?.ForgotPassword, Is.EqualTo(false)); + Assert.That(actualLogin?.Password, Is.EqualTo(string.Empty)); + Assert.That(actualLogin?.RequestTfaRemoval, Is.EqualTo(false)); + Assert.That(actualLogin?.SecurityCode, Is.EqualTo(string.Empty)); + } + + [Test] + public async Task LoginGet_WhenLoginIncluded_ReturnsLoginViewWithCorrectModel() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + Login? login = new Login + { + Email = "TestUser@Test.test" + }; + + //Act + var response = await _accountController.LoginGet(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.EqualTo(login)); + } + + + [Test] + public async Task LoginGet_WhenSsoIdCookieExists_RedirectsToSsoLoginUrl() + { + //Arrange + Login? login = null; + + var ssoProviderId = 1; + var ssoUrl = "http://test.test/login"; + + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => ssoProviderId); + _singleSignOnMock.Setup(x => x.StartSingleSignOn(ssoProviderId, It.IsAny())) + .ReturnsAsync(() => ssoUrl); + + //Act + var response = await _accountController.LoginGet(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + + var redirectResult = response as RedirectResult; + Assert.That( redirectResult?.Url, Is.EqualTo(ssoUrl)); + + _cookieManagerMock.Verify( x => x.DeleteSsoIdCookie(It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LoginPostUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LoginPostUnitTests.cs new file mode 100644 index 0000000..23fb4b6 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LoginPostUnitTests.cs @@ -0,0 +1,209 @@ +using e_suite.API.Common.models; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class LoginPostUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LoginPost_WhenLoginPasswordEmptyAndNotSingleSignOn_ReturnsLoginViewWithEmptyModel() + { + //Arrange + var login = new Login + { + Email = "Test@test.test" + }; + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.EqualTo(login)); + } + + [Test] + public async Task LoginPost_WhenSingleSignOnUserPresentsEmail_ReturnsRedirectsToSingleSignOnUrl() + { + //Arrange + var login = new Login + { + Email = "Test@test.test" + }; + + var ssoUrl = "http://test.test/login"; + + _singleSignOnMock.Setup(x => x.StartSingleSignOn(login.Email, It.IsAny())) + .ReturnsAsync(() => ssoUrl); + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo(ssoUrl)); + } + + [Test] + public async Task LoginPost_WhenForgotPassword_UserManagerForgotPasswordCalled() + { + //Arrange + Login? login = new Login + { + Email = "TestUser@Test.test", + ForgotPassword = true + }; + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.EqualTo(login)); + + _userManagerMock.Verify(x => x.ForgotPassword(login.Email, It.IsAny()), Times.Once); + } + + [Test] + public async Task LoginPost_WhenForgotPasswordButPasswordHasRubbish_UserManagerForgotPasswordCalled() + { + //Arrange + Login? login = new Login + { + Email = "TestUser@Test.test", + Password = "A", + ForgotPassword = true + }; + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.EqualTo(login)); + + _userManagerMock.Verify(x => x.ForgotPassword(login.Email, It.IsAny()), Times.Once); + } + + + [Test] + public async Task LoginPost_WhenPasswordPresentAndCorrect_CreatesSessionCookieAndRedirectToRoot() + { + //Arrange + Login? login = new Login + { + Email = "TestUser@Test.test", + Password = "SuperSecret" + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.Success, + Token = "Valid JSON Web Token" + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("/")); + + _cookieManagerMock.Verify( x => x.CreateSessionCookie(It.IsAny(), loginResponse), Times.Once); + } + + [TestCase(LoginResult.EmailNotConfirmed)] + [TestCase(LoginResult.TwoFactorAuthenticationRemovalRequested)] + [TestCase(LoginResult.TwoFactorAuthenticationCodeRequired)] + [TestCase(LoginResult.TwoFactorAuthenticationCodeIncorrect)] + public async Task LoginPost_WhenNonSsoLoginNotCompleted_ReturnsUpdatedView( LoginResult loginResult) + { + //Arrange + Login? login = new Login + { + Email = "TestUser@Test.test", + Password = "SuperSecret" + }; + + var loginResponse = new LoginResponse + { + Result = loginResult + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.EqualTo(login)); + } + + [Test] + public async Task LoginPost_WhenLoginFails_LogsBadLoginAttemptAndReturnsUpdatedView() + { + //Arrange + Login? login = new Login + { + Email = "TestUser@Test.test", + Password = "SuperSecret" + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.Failed + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.LoginPost(login, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Login")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualLogin = viewResult?.Model as Login; + Assert.That(actualLogin, Is.EqualTo(login)); + + _sentinelMock.Verify( x => x.LogBadRequest(_accountController, It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LogoutUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LogoutUnitTests.cs new file mode 100644 index 0000000..76e4a38 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/LogoutUnitTests.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class LogoutUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task Logout_WhenCalled_DeletesBrowserCookiesAndRedirectsToRoot() + { + //Arrange + + //Act + var response = await _accountController.Logout(CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/")); + + _cookieManagerMock.Verify(x => x.DeleteSessionCookie(It.IsAny()), Times.Once); + _cookieManagerMock.Verify(x => x.DeleteSsoIdCookie(It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/ProfileGetUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/ProfileGetUnitTests.cs new file mode 100644 index 0000000..35eecaf --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/ProfileGetUnitTests.cs @@ -0,0 +1,58 @@ +using e_suite.API.Common.models; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class ProfileGetUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LoginGet_WhenLoginNotPresent_ReturnsLoginViewWithEmptyModel() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var userProfile = new UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 2 + }; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())) + .ReturnsAsync(() => userProfile); + + //Act + var response = await _accountController.ProfileGet(CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var viewResult = response as ViewResult; + Assert.That(viewResult?.ViewName, Is.EqualTo("Profile")); + Assert.That(viewResult?.Model, Is.TypeOf()); + + var actualProfile = viewResult?.Model as Models.UserProfile; + Assert.That(actualProfile, Is.Not.Null); + Assert.That(actualProfile?.Email, Is.EqualTo(userProfile.Email)); + Assert.That(actualProfile?.FirstName, Is.EqualTo(userProfile.FirstName)); + Assert.That(actualProfile?.MiddleNames, Is.EqualTo(userProfile.MiddleNames)); + Assert.That(actualProfile?.LastName, Is.EqualTo(userProfile.LastName)); + Assert.That(actualProfile?.SsoProviderId, Is.EqualTo(userProfile.SsoProviderId)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/ProfilePostUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/ProfilePostUnitTests.cs new file mode 100644 index 0000000..da4608e --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/ProfilePostUnitTests.cs @@ -0,0 +1,210 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; +using UserProfile = eSuite.API.Models.UserProfile; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class ProfilePostUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ProfilePost_WhenSsoIdNotChanged_UpdatesProfileThenRedirectsToProfileGet() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var userProfile = new UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 2 + }; + + var savedUserProfile = new e_suite.API.Common.models.UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 2 + }; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())) + .ReturnsAsync(() => savedUserProfile); + + //Act + var response = await _accountController.ProfilePost(userProfile, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/account/profile")); + + _userManagerMock.Verify(x => x.TurnOfSsoForUser(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + _userManagerMock.Verify( x => x.UpdateProfile(It.IsAny(), email, It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task ProfilePost_WhenSsoIdSetToRemoved_UpdatesProfileRemovesSsoLinkThenRedirectToProfileGet() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var userProfile = new UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = -1 + }; + + var savedUserProfile = new e_suite.API.Common.models.UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 2 + }; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())) + .ReturnsAsync(() => savedUserProfile); + + //Act + var response = await _accountController.ProfilePost(userProfile, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/account/profile")); + + _userManagerMock.Verify(x => x.TurnOfSsoForUser(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _userManagerMock.Verify(x => x.UpdateProfile(It.IsAny(), email, It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task ProfilePost_WhenSsoIdChanged_UpdatesProfileThenStartsProcessOfLinkingTheNewSsoProvider() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var userProfile = new UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 3 + }; + + var savedUserProfile = new e_suite.API.Common.models.UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 2 + }; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())) + .ReturnsAsync(() => savedUserProfile); + + var ssoUrl = "ssoUrl"; + + _singleSignOnMock.Setup(x => x.StartSingleSignOn(userProfile.SsoProviderId, It.IsAny())) + .ReturnsAsync(() => ssoUrl); + + //Act + var response = await _accountController.ProfilePost(userProfile, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo(ssoUrl)); + + _cookieManagerMock.Verify( + x => x.CreateProfileLinkCookie(It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny()), Times.Once); + _userManagerMock.Verify(x => x.TurnOfSsoForUser(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + _userManagerMock.Verify(x => x.UpdateProfile(It.IsAny(), email, It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task ProfilePost_WhenUpdatedSsoIdIsInvalid_SkipsUpdatingTheSsoLink() + { + //Arrange + _cookieManagerMock.Setup(x => x.GetSsoIdFromSsoIdCookie(It.IsAny())).ReturnsAsync(() => null); + + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var userProfile = new UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 3 + }; + + var savedUserProfile = new e_suite.API.Common.models.UserProfile + { + Email = "Test@test.test", + FirstName = "Testy", + MiddleNames = "The tested", + LastName = "McTester", + SsoProviderId = 2 + }; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())) + .ReturnsAsync(() => savedUserProfile); + + _singleSignOnMock.Setup(x => x.StartSingleSignOn(userProfile.SsoProviderId, It.IsAny())) + .ReturnsAsync(() => null!); + + //Act + var response = await _accountController.ProfilePost(userProfile, CancellationToken.None); + + //Assert + Assert.That(response, Is.TypeOf()); + var redirectResult = response as RedirectResult; + Assert.That(redirectResult?.Url, Is.EqualTo("~/account/profile")); + + _cookieManagerMock.Verify( + x => x.CreateProfileLinkCookie(It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny()), Times.Never); + _userManagerMock.Verify(x => x.TurnOfSsoForUser(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + _userManagerMock.Verify(x => x.UpdateProfile(It.IsAny(), email, It.IsAny(), It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/RefreshTokenUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/RefreshTokenUnitTests.cs new file mode 100644 index 0000000..a2839d9 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AccountControllerUnitTests/RefreshTokenUnitTests.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AccountControllerUnitTests; + +[TestFixture] +public class RefreshTokenUnitTests : AccountControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task RefreshToken_WhenCalledGeneratesNewToken() + { + //Arrange + var userId = 99; + var email = "email@mail.test"; + var displayName = "Testy McTester"; + AddAuthorisedUserToController(userId, email, displayName); + + var loginResponse = new LoginResponse + { + Result = LoginResult.Success, + Token = "Json Web Toke goes here" + }; + + + _userManagerMock.Setup(x => x.RefreshToken(It.IsAny(), It.IsAny())) + .ReturnsAsync(() => loginResponse); + + //Act + var response = await _accountController.RefreshToken(CancellationToken.None); + + //Assert + _cookieManagerMock.Verify( x => x.CreateSessionCookie(It.IsAny(), loginResponse), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuditControllerUnitTests/AuditControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuditControllerUnitTests/AuditControllerTestBase.cs new file mode 100644 index 0000000..2fe1f11 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuditControllerUnitTests/AuditControllerTestBase.cs @@ -0,0 +1,38 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.AuditControllerUnitTests; + +public abstract class AuditControllerTestBase : TestBase +{ + protected Mock _auditLogMock = null!; + protected AuditController _auditController = null!; + + public override async Task Setup() + { + await base.Setup(); + _auditLogMock = new Mock(); + _auditController = new AuditController(_auditLogMock.Object); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _auditController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuditControllerUnitTests/AuditControllerUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuditControllerUnitTests/AuditControllerUnitTests.cs new file mode 100644 index 0000000..080b56c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuditControllerUnitTests/AuditControllerUnitTests.cs @@ -0,0 +1,56 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AuditControllerUnitTests; + +[TestFixture] +public class AuditControllerUnitTests : AuditControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task Get_WhenCalled_ReturnsPagedData() + { + //Arrange + var auditLogs = new List + { + new() + { + Id = 999, + Comment = string.Empty, + DisplayName = "Testy McTester" + } + }; + + var paginatedData = new PaginatedData + { + Count = auditLogs.Count, + Data = auditLogs, + Page = 1, + PageSize = 10 + }; + + var logEntry = string.Empty; + bool primaryOnly = false; + + _auditLogMock.Setup(x => x.GetAuditLogEntries(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _auditController.Get(new Paging(), logEntry, primaryOnly, CancellationToken.None); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/AuthenticationControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/AuthenticationControllerTestBase.cs new file mode 100644 index 0000000..abc0098 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/AuthenticationControllerTestBase.cs @@ -0,0 +1,45 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.Service.Sentinel; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.AuthenticationControllerUnitTests; + +public abstract class AuthenticationControllerTestBase : TestBase +{ + protected AuthenticationController _authenticationController = null!; + protected Mock _userManagerMock = null!; + protected Mock _sentinelMock = null!; + + protected const string AccessDeniedText = "Access denied"; + protected const string LoginAcceptedText = "Login accepted"; + + public override async Task Setup() + { + await base.Setup(); + + _userManagerMock = new Mock(); + _sentinelMock = new Mock(); + + _authenticationController = new AuthenticationController(_userManagerMock.Object, _sentinelMock.Object); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity([ + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + ], "TestAuthentication")); + + _authenticationController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/CompleteEmailActionUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/CompleteEmailActionUnitTests.cs new file mode 100644 index 0000000..861ab1e --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/CompleteEmailActionUnitTests.cs @@ -0,0 +1,119 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AuthenticationControllerUnitTests; + +[TestFixture] +public class CompleteEmailActionUnitTests : AuthenticationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CompleteEmailAction_PasswordResetAndPasswordNotSupplied_ReturnsBadRequest() + { + //Arrange + var token = new EmailActionToken + { + Email = "forgetful.user@sun-strategy.com", + Token = new Guid("{522E20CB-52AC-456B-BD6C-E1D65F9DAA83}") + }; + + var detailMessage = "Password missing"; + + _userManagerMock.Setup(x => x.CompleteEmailAction(token, It.IsAny())).Throws(new ArgumentException(detailMessage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _authenticationController.CompleteEmailAction(token); + }); + } + + [Test] + public void CompleteEmailAction_TokenInvalid_ReturnsBadRequest() + { + //Arrange + var token = new EmailActionToken + { + Email = "evil.hacker@sun-strategy.com", + Token = new Guid("{522E20CB-52AC-456B-BD6C-E1D65F9DAA83}") + }; + + _userManagerMock.Setup(x => x.CompleteEmailAction(token, It.IsAny())).Throws(new TokenInvalidException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _authenticationController.CompleteEmailAction(token); + }); + } + + [Test] + public void CompleteEmailAction_EmailDoesNotMatchToken_ReturnsBadRequest() + { + //Arrange + var token = new EmailActionToken + { + Email = "evil.hacker@sun-strategy.com", + Token = new Guid("{522E20CB-52AC-456B-BD6C-E1D65F9DAA83}") + }; + + _userManagerMock.Setup(x => x.CompleteEmailAction(token, It.IsAny())).Throws(new InvalidEmailException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _authenticationController.CompleteEmailAction(token); + }); + } + + [Test] + public async Task CompleteEmailAction_GoodRequest_ReturnsOK() + { + //Arrange + var token = new EmailActionToken + { + Email = "evil.hacker@sun-strategy.com", + Token = new Guid("{522E20CB-52AC-456B-BD6C-E1D65F9DAA83}") + }; + + //Act + var actualResult = await _authenticationController.CompleteEmailAction(token); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + + var objectResult = actualResult as OkResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } + + [Test] + public async Task CompleteEmailAction_SentinelGetsInvolved_ReturnsSentinelsResult() + { + //Arrange + var token = new EmailActionToken + { + Email = "evil.hacker@sun-strategy.com", + Token = new Guid("{522E20CB-52AC-456B-BD6C-E1D65F9DAA83}") + }; + + _sentinelMock.Setup(x => x.CheckSecurity(_authenticationController, It.IsAny())).Returns((controller, cancellationToken) => Task.FromResult(controller.Unauthorized())); + + //Act + var actualResult = await _authenticationController.CompleteEmailAction(token); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/ForgotPasswordUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/ForgotPasswordUnitTests.cs new file mode 100644 index 0000000..4d14a76 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/ForgotPasswordUnitTests.cs @@ -0,0 +1,88 @@ +using e_suite.API.Common.exceptions; +using eSuite.API.Models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AuthenticationControllerUnitTests; + +[TestFixture] +public class ForgotPasswordUnitTests : AuthenticationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ForgotPassword_EmailFound_ReturnsOK() + { + //Arrange + var forgotPasswordRequest = new EmailAddress + { + Email = "test@test.test" + }; + + //Act + var actualResult = await _authenticationController.ForgotPassword(forgotPasswordRequest); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public async Task ForgotPassword_SentinelGetsInvolved_ReturnsSentinelsResult() + { + //Arrange + var forgotPasswordRequest = new EmailAddress + { + Email = "test@test.test" + }; + + _sentinelMock.Setup(x => x.CheckSecurity(_authenticationController, It.IsAny())).Returns((controller, cancellationToken) => Task.FromResult(controller.Unauthorized())); + + //Act + var actualResult = await _authenticationController.ForgotPassword(forgotPasswordRequest); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedResult))); + } + + [Test] + public void ForgotPassword_EmailNotFound_ReturnsBadRequest() + { + //Arrange + var forgotPasswordRequest = new EmailAddress + { + Email = "test@test.test" + }; + + _userManagerMock.Setup(x => x.ForgotPassword(forgotPasswordRequest.Email, It.IsAny())).Throws(new NotFoundException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _authenticationController.ForgotPassword(forgotPasswordRequest); + }); + } + + [Test] + public async Task ForgotPassword_EmailNotConfirmed_ReturnsBadRequest() + { + //Arrange + var forgotPasswordRequest = new EmailAddress + { + Email = "test@testy.test" + }; + + _userManagerMock.Setup(x => x.ForgotPassword(forgotPasswordRequest.Email, It.IsAny())).Throws(new EmailNotConfirmedException()); + + //Act + var actualResult = await _authenticationController.ForgotPassword(forgotPasswordRequest); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedObjectResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/LoginUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/LoginUnitTests.cs new file mode 100644 index 0000000..0516534 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/LoginUnitTests.cs @@ -0,0 +1,279 @@ +using e_suite.API.Common.models; +using eSuite.API.Models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AuthenticationControllerUnitTests; + +[TestFixture] +public class LoginUnitTests : AuthenticationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [TestCase("test@test.com")] + [TestCase("hacker@evilwebsite.org")] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_EmailNotFound_Unauthorised(string emailAddress) + { + //Arrange + var login = new Login + { + Email = emailAddress, + Password = string.Empty + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.Failed + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).Returns(Task.FromResult(loginResponse)); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedObjectResult))); + + var objectResult = actualResult as UnauthorizedObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(401)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(ProblemDetails))); + + var problemDetails = objectResult.Value as ProblemDetails; + + Assert.That(problemDetails?.Title, Is.EqualTo(AccessDeniedText)); + } + } + + [TestCase("testuser1@sun-strategy.com")] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_Success_OKAndToken(string emailAddress) + { + //Arrange + var login = new Login + { + Email = emailAddress, + Password = string.Empty + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.Success, + Token = "This is a test token" + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).Returns(Task.FromResult(loginResponse)); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(SuccessfulLogin))); + + var problemDetails = objectResult.Value as SuccessfulLogin; + + Assert.That(problemDetails?.Title, Is.EqualTo(LoginAcceptedText)); + Assert.That(problemDetails?.Token, Is.EqualTo(loginResponse.Token)); + } + } + + [TestCase("testuser1@sun-strategy.com")] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_TwoFactorAuthenticationCodeIncorrect_Unauthorised(string emailAddress) + { + //Arrange + var login = new Login + { + Email = emailAddress, + Password = string.Empty, + SecurityCode = "12345" + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.TwoFactorAuthenticationCodeIncorrect + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).Returns(Task.FromResult(loginResponse)); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedObjectResult))); + + var objectResult = actualResult as UnauthorizedObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(401)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(ProblemDetails))); + + var problemDetails = objectResult.Value as ProblemDetails; + + Assert.That(problemDetails?.Title, Is.EqualTo(AccessDeniedText)); + } + } + + [TestCase("testuser1@sun-strategy.com")] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_TwoFactorAuthenticationCodeRequired_AcceptedWithDetails(string emailAddress) + { + //Arrange + var login = new Login + { + Email = emailAddress, + Password = string.Empty + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.TwoFactorAuthenticationCodeRequired + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).Returns(Task.FromResult(loginResponse)); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(AcceptedResult))); + + var objectResult = actualResult as AcceptedResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(202)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(ProblemDetails))); + + var problemDetails = objectResult.Value as ProblemDetails; + + Assert.That(problemDetails?.Title, Is.EqualTo(LoginAcceptedText)); + Assert.That(problemDetails?.Detail, Is.EqualTo("Please supply Two Factor Authentication code")); + } + } + + [TestCase("testuser1@sun-strategy.com")] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_TwoFactorAuthenticationRemovalRequested_AcceptedWithDetails(string emailAddress) + { + //Arrange + var login = new Login + { + Email = emailAddress, + Password = string.Empty, + RequestTfaRemoval = true + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.TwoFactorAuthenticationRemovalRequested + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).Returns(Task.FromResult(loginResponse)); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(AcceptedResult))); + + var objectResult = actualResult as AcceptedResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(202)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(ProblemDetails))); + + var problemDetails = objectResult.Value as ProblemDetails; + + Assert.That(problemDetails?.Title, Is.EqualTo(LoginAcceptedText)); + Assert.That(problemDetails?.Detail, Is.EqualTo("Request to remove two factor authentication accepted")); + } + } + + [TestCase("testuser1@sun-strategy.com")] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_EmailNotConfirmed_AcceptedWithDetails(string emailAddress) + { + //Arrange + var login = new Login + { + Email = emailAddress, + Password = string.Empty, + SecurityCode = "12345" + }; + + var loginResponse = new LoginResponse + { + Result = LoginResult.EmailNotConfirmed + }; + + _userManagerMock.Setup(x => x.Login(login, It.IsAny())).Returns(Task.FromResult(loginResponse)); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedObjectResult))); + + var objectResult = actualResult as UnauthorizedObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(401)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(ProblemDetails))); + + var problemDetails = objectResult.Value as ProblemDetails; + + Assert.That(problemDetails?.Title, Is.EqualTo("Access denied")); + Assert.That(problemDetails?.Detail, Is.EqualTo("Email not confirmed")); + } + } + + [Test] + [Obsolete("_authenticationController.Login is obsolete")] + public async Task Login_SentinelGetsInvolved_ReturnsSentinelsResult() + { + //Arrange + var login = new Login + { + Email = "test@test.test" + }; + + _sentinelMock.Setup(x => x.CheckSecurity(_authenticationController, It.IsAny())).Returns((controller, cancellationToken) => Task.FromResult(controller.Unauthorized())); + + //Act + var actualResult = await _authenticationController.Login(login); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/RefreshTokenUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/RefreshTokenUnitTests.cs new file mode 100644 index 0000000..18e7abe --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/AuthenticationControllerUnitTests/RefreshTokenUnitTests.cs @@ -0,0 +1,113 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.API.Models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.AuthenticationControllerUnitTests; + +[TestFixture] +public class RefreshTokenUnitTests : AuthenticationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task RefreshToken_UserIdNotFound_Unauthorised() + { + //Arrange + const long id = 2; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + + var loginResponse = new LoginResponse + { + Result = LoginResult.Failed + }; + + _userManagerMock.Setup(x => x.RefreshToken(It.IsAny(), It.IsAny())).Returns( (generalIdRef, cancellationToken) => + { + if (generalIdRef is { Id: id }) + { + return Task.FromResult(loginResponse); + } + + throw new NotFoundException(); + }); + + //Act + var actualResult = await _authenticationController.RefreshToken(); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(UnauthorizedObjectResult))); + + var objectResult = actualResult as UnauthorizedObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(401)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(ProblemDetails))); + + var problemDetails = objectResult.Value as ProblemDetails; + + Assert.That(problemDetails?.Title, Is.EqualTo(AccessDeniedText)); + } + } + + [Test] + public async Task RefreshToken_Success_OKAndToken() + { + //Arrange + const long id = -1; + const string email = "testuser1@sun-strategy.com"; + const string displayName = "Test1 User"; + + AddAuthorisedUserToController(id, email, displayName); + + var loginResponse = new LoginResponse + { + Result = LoginResult.Success, + Token = "This is a test token" + }; + + _userManagerMock.Setup(x => x.RefreshToken(It.IsAny(), It.IsAny())).Returns((generalIdRef, cancellationToken) => + { + if (generalIdRef is { Id: id }) + { + return Task.FromResult(loginResponse); + } + + throw new NotFoundException(); + }); + + //Act + var actualResult = await _authenticationController.RefreshToken(); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(SuccessfulLogin))); + + var problemDetails = objectResult.Value as SuccessfulLogin; + + Assert.That(problemDetails?.Title, Is.EqualTo("Access Granted")); + Assert.That(problemDetails?.Token, Is.EqualTo(loginResponse.Token)); + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/BlockedIPsControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/BlockedIPsControllerTestBase.cs new file mode 100644 index 0000000..ea12034 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/BlockedIPsControllerTestBase.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System.Security.Claims; + +namespace eSuite.API.UnitTests.Controllers.BlockedIPsControllerUnitTests; + +public abstract class BlockedIPsControllerTestBase: TestBase +{ + protected Mock _blockedIPsManagerMock = null!; + protected BlockedIPsController _blockedIPsController = null!; + + public override async Task Setup() + { + await base.Setup(); + _blockedIPsManagerMock = new Mock(); + _blockedIPsController = new BlockedIPsController(_blockedIPsManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Test User"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + }, "TestAuthentication")); + + _blockedIPsController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/GetBlockedIPsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/GetBlockedIPsUnitTests.cs new file mode 100644 index 0000000..7a0b03c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/GetBlockedIPsUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.BlockedIPsControllerUnitTests; + +[TestFixture] +public class GetBlockedIPsUnitTests: BlockedIPsControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetBlockedIPs_NormalConditions_ReturnsOkObjResult() + { + //Arrange + var paginatedData = new PaginatedData + { + Count = 2, + Data = new List { new() }, + Page = 1, + PageSize = 10 + }; + + _blockedIPsManagerMock?.Setup(x => x.GetBlockedIPs(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + var paging = new Paging(); + + //Act + var res = await _blockedIPsController.Get(paging); + + //Assert + Assert.That(res, Is.Not.Null); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/UnblockIPAddressUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/UnblockIPAddressUnitTests.cs new file mode 100644 index 0000000..c894f21 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/BlockedIPsControllerUnitTests/UnblockIPAddressUnitTests.cs @@ -0,0 +1,33 @@ +using e_suite.Database.Audit; +using eSuite.API.Models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.BlockedIPsControllerUnitTests; + +[TestFixture] +public class UnblockIPAddressUnitTests: BlockedIPsControllerTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task UnblockIPAddress_NormanConditions_Returns200OkObjResult() + { + //Arrange + var blockedIPAddress = new BlockedIPAddress + { + IpAddress = "127.0.0.1" + }; + var cancellationToken = CancellationToken.None; + + _blockedIPsManagerMock?.Setup(x => x.UnblockIPAddress(It.IsAny(), blockedIPAddress.IpAddress, It.IsAny())).Returns(Task.CompletedTask); + + //Act + var res = await _blockedIPsController.Delete(blockedIPAddress, cancellationToken); + + //Assert + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/CreateCustomFieldUnitTest.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/CreateCustomFieldUnitTest.cs new file mode 100644 index 0000000..6543e3c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/CreateCustomFieldUnitTest.cs @@ -0,0 +1,127 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.CustomFieldControllerUnitTest; + +[TestFixture] +public class CreateCustomFieldUnitTest : CustomFieldControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateCustomField_WithPredifaindGuid_RetunrOK() + { + //Arrange + var guid = new Guid("37c6853a-3ff3-49d2-94b0-d07944f7b53d"); + var createCustomFieldModel = new CreateCustomField + { + Guid = guid, + DefaultValue = "Name", + Name = "Name" + }; + + //Act + var res = await _customFieldController.CreateField(createCustomFieldModel); + + //Assert + _customFieldManagerMock?.Verify(x => x.CreateFieldAsync(It.IsAny(), It.Is(x => x.Name == "Name" && x.Guid == guid), default)); + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public void CreateCustomField_ExistingGuid_Returns404() + { + //Arrange + const string errorMessage = "Guid error"; + + var guid = new Guid("d8554de5-073d-4169-9442-9f71f494dd87"); + var createCustomFieldModel = new CreateCustomField + { + Guid = guid, + DefaultValue = "Name", + Name = "Name" + }; + _customFieldManagerMock?.Setup(x => x.CreateFieldAsync(It.IsAny(), It.Is(x => x.Guid == guid), default)).ThrowsAsync(new ExistsException(errorMessage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _customFieldController.CreateField(createCustomFieldModel); + }); + + } + + [Test] + public async Task CreateCustomField_AutoGenGuid_Returns200() + { + //Arrange + var createCustomFieldModel = new CreateCustomField + { + Guid = null, + DefaultValue = "Name", + Name = "Name", + FieldType = Core.CustomFields.FieldType.Text + }; + + //Act + var res = await _customFieldController.CreateField(createCustomFieldModel); + + //Assert + _customFieldManagerMock?.Verify(x => x.CreateFieldAsync(It.IsAny(), It.Is(x => x.Guid == null && x.DefaultValue == "Name" && x.Name == "Name"), default)); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public void CreateField_NameExists_Return404() + { + //Arrange + const string errorMesage = "Name Exists"; + + var createCustomFieldModel = new CreateCustomField + { + Guid = null, + DefaultValue = "Name", + Name = "Name", + FieldType = Core.CustomFields.FieldType.Text + }; + _customFieldManagerMock?.Setup(x => x.CreateFieldAsync(It.IsAny(), It.Is(x => x.Name == "Name" && x.DefaultValue == "Name"), default)).ThrowsAsync(new ExistsException(errorMesage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _customFieldController.CreateField(createCustomFieldModel); + }); + } + + [Test] + public async Task CreateField_PredefinedGuid_Returns200() + { + //Arrange + var guid = new Guid("09371a16-6094-4e8d-83ca-ef0ac2092a8d"); + + var createCustomFieldModel = new CreateCustomField + { + Guid = guid, + DefaultValue = "Name", + Name = "Name", + FieldType = Core.CustomFields.FieldType.Text + }; + + //Act + var res = await _customFieldController.CreateField(createCustomFieldModel); + + //Assert + _customFieldManagerMock?.Verify(x => x.CreateFieldAsync(It.IsAny(), It.Is(x => x.Guid == guid && x.Name == "Name"), It.IsAny())); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkResult))); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/CustomFieldControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/CustomFieldControllerTestBase.cs new file mode 100644 index 0000000..2ca60f5 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/CustomFieldControllerTestBase.cs @@ -0,0 +1,55 @@ +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System.Security.Claims; +using e_suite.API.Common; + +namespace eSuite.API.UnitTests.Controllers.CustomFieldControllerUnitTest; + +public abstract class CustomFieldControllerTestBase : TestBase +{ + protected CustomFieldsController _customFieldController; + protected Mock? _customFieldManagerMock; + + protected const string BadRequestText = "Bad request"; + protected const string NotFoundText = "Not found"; + + protected CustomFieldControllerTestBase() + { + _customFieldManagerMock = new Mock(); + + _customFieldController = new CustomFieldsController(_customFieldManagerMock.Object); + } + + public override async Task Setup() + { + await base.Setup(); + + _customFieldManagerMock = new Mock(); + _customFieldController = new CustomFieldsController(_customFieldManagerMock.Object); + + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _customFieldController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/DeactivateCustomFieldUnitTest.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/DeactivateCustomFieldUnitTest.cs new file mode 100644 index 0000000..17c4cae --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/DeactivateCustomFieldUnitTest.cs @@ -0,0 +1,76 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.CustomFieldControllerUnitTest; + +[TestFixture] +public class DeactivateCustomFieldUnitTest : CustomFieldControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeactivateCustomField_NotFound_Returns404() + { + //Arrange + const string errorText = "There is no CustomField with this Id"; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("220bd77a-e9d2-45aa-a50f-54a983cda0a6"), + Id = 5, + }; + _customFieldManagerMock?.Setup(x => x.DeleteFieldAsync(It.IsAny(), generalIdRef, default)).ThrowsAsync(new NotFoundException(errorText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _customFieldController.DeleteField(generalIdRef); + }); + } + + [Test] + public async Task DeactivateCustomField_BouthId_Returns200() + { + //Arrange + var genralId = new GeneralIdRef + { + Guid = new Guid("d558ef68-7685-4d8d-a8d2-ccdbdf1009c3"), + Id = 5, + }; + _customFieldManagerMock?.Setup(x => x.DeleteFieldAsync(It.IsAny(), genralId, default)).Returns(Task.CompletedTask); + + //Act + var res = await _customFieldController.DeleteField(genralId); + + //Assert + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public async Task EditCustomField_IdOnlyGuidId_Returns200() + { + //Arrange + var guid = new Guid("7e73f9d8-7ce3-4723-978c-99244af7c350"); + var generalIdRef = new GeneralIdRef + { + Guid = guid, + Id = null, + }; + _customFieldManagerMock?.Setup(x => x.DeleteFieldAsync(It.IsAny(), It.Is(x => x.Guid == guid), default)).Returns(Task.CompletedTask); + + //Act + var res = await _customFieldController.DeleteField(generalIdRef); + + //Assert + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/EditCustomFieldUnitTest.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/EditCustomFieldUnitTest.cs new file mode 100644 index 0000000..372501e --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/EditCustomFieldUnitTest.cs @@ -0,0 +1,90 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.CustomFieldControllerUnitTest; + +[TestFixture] +public class EditCustomFieldUnitTest : CustomFieldControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditCustomField_EverythingOk_ReturnsOk() + { + //Arrange + var editModel = new EditCustomFields + { + Id = new GeneralIdRef + { + Guid = new Guid("b87c50a6-09d4-4790-a158-24a477e91400") + }, + DefaultValue = "Name" + }; + + //Act + var res = await _customFieldController.EditField(editModel); + + //Assert + _customFieldManagerMock?.Verify(x => x.EditFieldAsync(It.IsAny(), editModel, It.IsAny()), Times.Once()); + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + + } + + [Test] + public void EditCustomField_IdNotFound_Rturn404() + { + //Arrange + const string errorText = "There is no CustomField with this Id"; + var editModel = new EditCustomFields + { + Id = new GeneralIdRef + { + Guid = new Guid("e2d8e755-8344-4577-b7c2-33a04d440915") + }, + DefaultValue = "Name" + }; + _customFieldManagerMock?.Setup(x => x.EditFieldAsync(It.IsAny(), editModel, It.IsAny())).ThrowsAsync(new NotFoundException(errorText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _customFieldController.EditField(editModel); + }); + } + + [Test] + public void EditCustomField_NameExistsOnDiffrentField_Returns400() + { + //Arrange + const string errorText = "Name Exists"; + var guid = new Guid("ad94a15f-df9b-4352-aafd-8f7726204ed7"); + + var editModel = new EditCustomFields + { + Id = new GeneralIdRef + { + Guid = guid + }, + DefaultValue = "Name", + Name = "Name" + }; + _customFieldManagerMock?.Setup(x => x.EditFieldAsync(It.IsAny(), It.Is(x => x.Id.Guid == guid && x.Name == "Name"), It.IsAny())).ThrowsAsync(new ExistsException(errorText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _customFieldController.EditField(editModel); + }); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/GetCustomFieldUnitTest.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/GetCustomFieldUnitTest.cs new file mode 100644 index 0000000..77d30ec --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/GetCustomFieldUnitTest.cs @@ -0,0 +1,177 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.CustomFieldControllerUnitTest; + +[TestFixture] +public class GetCustomFieldUnitTest : CustomFieldControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetCustomField_ByGuidOnly_ReturnOk() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + var guid = new Guid("96ff68c5-0b1d-4956-9464-8af65ef1d7ea"); + + AddAuthorisedUserToController(id, email, displayName); + var idRef = new GeneralIdRef + { + Guid = guid, + Id = null + }; + + //Act + var res = await _customFieldController.GetField(idRef); + + //Assert + _customFieldManagerMock?.Verify(x => x.GetFieldAsync(It.Is(x => x.Guid == guid), default), Times.Once()); + Assert.That(res, Is.Not.Null); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + } + + [Test] + public async Task GetCustomField_ByOnlyId_ReturnsOk() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + var idNum = 5; + + AddAuthorisedUserToController(id, email, displayName); + var idRef = new GeneralIdRef + { + Guid = null, + Id = idNum + }; + + //Act + var res = await _customFieldController.GetField(idRef); + + //Assert + _customFieldManagerMock?.Verify(x => x.GetFieldAsync(It.Is(x => x.Id == idNum), default), Times.Once()); + Assert.That(res, Is.Not.Null); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + } + + [Test] + public async Task GetCustomfield_NormalConditionsByOnlyIdNum_ReturnsRightObj() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + var idNum = 5; + var guid = new Guid("0d7c1b5b-d322-4ed2-aced-657c9ae3fd96"); + + AddAuthorisedUserToController(id, email, displayName); + var idRef = new GeneralIdRef + { + Guid = null, + Id = idNum + }; + var objRes = new CustomFieldDefinition + { + DefaultValue = "Default", + FieldType = Core.CustomFields.FieldType.Text, + Guid = guid, + Name = "Name" + }; + + _customFieldManagerMock?.Setup(x => x.GetFieldAsync(It.Is(x => x.Id == idNum), default)).ReturnsAsync(objRes); + + //Act + var res = await _customFieldController.GetField(idRef); + + //Assert + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = res as OkObjectResult; + Assert.That(objectResult?.Value, Is.Not.Null); + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType(), Is.EqualTo(typeof(CustomFieldDefinition))); + var field = objectResult?.Value as CustomFieldDefinition; + Assert.That(field?.Name, Is.EqualTo("Name")); + Assert.That(field?.Guid, Is.EqualTo(guid)); + } + } + + [Test] + public async Task GetCustomField_NormalConditionByOnlyGuidId_ReturnsRightObj() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + var guid = new Guid("5e2964ef-07d7-4e5e-b57d-4fc82d1c4e67"); + + AddAuthorisedUserToController(id, email, displayName); + var idRef = new GeneralIdRef + { + Guid = guid, + Id = null + }; + var objRes = new CustomFieldDefinition + { + DefaultValue = "Default", + FieldType = Core.CustomFields.FieldType.Text, + Guid = guid, + Name = "Name" + }; + + _customFieldManagerMock?.Setup(x => x.GetFieldAsync(It.Is(x => x.Guid == guid), default)).ReturnsAsync(objRes); + + //Act + var res = await _customFieldController.GetField(idRef); + + //Assert + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = res as OkObjectResult; + Assert.That(objectResult?.Value, Is.Not.Null); + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType(), Is.EqualTo(typeof(CustomFieldDefinition))); + var field = objectResult?.Value as CustomFieldDefinition; + Assert.That(field?.Name, Is.EqualTo("Name")); + } + } + + [Test] + public void GetCustomField_FieldIdNotFound_Retruns404() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + const string notFound = "field not found error"; + var guid = new Guid("e89d2a53-313e-4221-be0d-1df72b839d77"); + + AddAuthorisedUserToController(id, email, displayName); + var idRef = new GeneralIdRef + { + Guid = null, + Id = null + }; + _customFieldManagerMock?.Setup(x => x.GetFieldAsync(It.Is(x => x.Id == null && x.Guid == null), default)).ThrowsAsync(new NotFoundException(notFound)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _customFieldController.GetField(idRef); + }); + } + +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/GetFieldsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/GetFieldsUnitTests.cs new file mode 100644 index 0000000..5db4761 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/CustomFieldControllerUnitTest/GetFieldsUnitTests.cs @@ -0,0 +1,54 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.CustomFieldControllerUnitTest; + +[TestFixture] +public class GetFieldsUnitTests : CustomFieldControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetFields_WhenCalled_ReturnsPagedData() + { + //Arrange + var auditLogs = new List + { + new() + { + Guid = new Guid("e7b1cc1a-0325-46fa-8bff-fa168cfe8dd9"), + Id = 999, + Name = "Test custom field" + } + }; + + var paginatedData = new PaginatedData + { + Count = auditLogs.Count, + Data = auditLogs, + Page = 1, + PageSize = 10 + }; + + + _customFieldManagerMock!.Setup(x => x.GetFieldsAsync(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _customFieldController.GetFields(new Paging(), CancellationToken.None); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/CreateDomainUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/CreateDomainUnitTests.cs new file mode 100644 index 0000000..efe803f --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/CreateDomainUnitTests.cs @@ -0,0 +1,37 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.DomainControllerUnitTests; + +[TestFixture] +public class CreateDomainUnitTests : DomainControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetDomain_WhenCalled_ReturnsOKResult() + { + //Arrange + var createDomain = new CreateDomain + { + Guid = new Guid("f6bfa906-a4f6-41a0-bbad-06b77af8ac50") + }; + + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _domainController.CreateDomain(createDomain, cancellationToken); + + //Assert + _domainManagerMock.Verify(x => x.CreateDomainAsync(It.IsAny(), createDomain, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/DeleteDomainUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/DeleteDomainUnitTests.cs new file mode 100644 index 0000000..2cf4a89 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/DeleteDomainUnitTests.cs @@ -0,0 +1,34 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.DomainControllerUnitTests; + +[TestFixture] +public class DeleteDomainUnitTests : DomainControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditDomain_WhenCalled_ReturnsOKResult() + { + //Arrange + var generalIdRef = new GeneralIdRef(); + + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _domainController.DeleteDomain(generalIdRef, cancellationToken); + + //Assert + _domainManagerMock.Verify(x => x.DeleteDomainAsync(It.IsAny(), generalIdRef, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/DomainControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/DomainControllerTestBase.cs new file mode 100644 index 0000000..2e782e8 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/DomainControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.DomainControllerUnitTests; + +public abstract class DomainControllerTestBase : TestBase +{ + protected Mock _domainManagerMock = null!; + protected DomainController _domainController = null!; + + public override async Task Setup() + { + await base.Setup(); + _domainManagerMock = new Mock(); + _domainController = new DomainController(_domainManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _domainController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/EditDomainUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/EditDomainUnitTests.cs new file mode 100644 index 0000000..bf25279 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/EditDomainUnitTests.cs @@ -0,0 +1,36 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.DomainControllerUnitTests; + +[TestFixture] +public class EditDomainUnitTests : DomainControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditDomain_WhenCalled_ReturnsOKResult() + { + //Arrange + var editDomain = new EditDomain + { + }; + + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _domainController.EditDomain(editDomain, cancellationToken); + + //Assert + _domainManagerMock.Verify(x => x.EditDomainAsync(It.IsAny(), editDomain, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/GetDomainUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/GetDomainUnitTests.cs new file mode 100644 index 0000000..816dd80 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/GetDomainUnitTests.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.DomainControllerUnitTests; + +[TestFixture] +public class GetDomainUnitTests : DomainControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetDomain_WhenCalled_ReturnsOKResultWithData() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("f6bfa906-a4f6-41a0-bbad-06b77af8ac50") + }; + + var cancellationToken = CancellationToken.None; + + var domain = new GetDomain(); + _domainManagerMock.Setup(x => x.GetDomainAsync(generalIdRef, cancellationToken)).ReturnsAsync(domain); + + //Act + var actualResult = await _domainController.GetDomain(generalIdRef, cancellationToken); + + //Assert + _domainManagerMock.Verify(x => x.GetDomainAsync(generalIdRef, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.EqualTo(domain)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/GetDomainsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/GetDomainsUnitTests.cs new file mode 100644 index 0000000..f4967d0 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/DomainControllerUnitTests/GetDomainsUnitTests.cs @@ -0,0 +1,55 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.DomainControllerUnitTests; + +[TestFixture] +public class GetDomainsUnitTests : DomainControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetDomains_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List + { + new() + { + Guid = new Guid("16241e96-9062-4221-b073-a48330b2cc9b"), + Id = 999, + Name = "Some domain" + } + }; + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + _domainManagerMock.Setup(x => x.GetDomainsAsync(It.IsAny(), cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _domainController.GetDomains(new Paging(), cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/ExceptionLogsControllerUnitTest/ExceptionLogsControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/ExceptionLogsControllerUnitTest/ExceptionLogsControllerTestBase.cs new file mode 100644 index 0000000..4c83df5 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/ExceptionLogsControllerUnitTest/ExceptionLogsControllerTestBase.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System.Security.Claims; + +namespace eSuite.API.UnitTests.Controllers.ExceptionLogsControllerUnitTest; + +public class ExceptionLogsControllerTestBase : TestBase +{ + protected Mock _exceptionLogManagerMock = null!; + protected ExceptionLogsController _exceptionLogsController = null!; + + public override async Task Setup() + { + await base.Setup(); + _exceptionLogManagerMock = new Mock(); + _exceptionLogsController = new ExceptionLogsController(_exceptionLogManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Test User"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + }, "TestAuthentication")); + + _exceptionLogsController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/ExceptionLogsControllerUnitTest/GetExceptionLogsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/ExceptionLogsControllerUnitTest/GetExceptionLogsUnitTests.cs new file mode 100644 index 0000000..0dd43a6 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/ExceptionLogsControllerUnitTest/GetExceptionLogsUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.ExceptionLogsControllerUnitTest; + +[TestFixture] +public class GetExceptionLogsUnitTests: ExceptionLogsControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetBlockedIPs_NormalConditions_ReturnsOkObjResult() + { + //Arrange + var paginatedData = new PaginatedData + { + Count = 2, + Data = new List { new() }, + Page = 1, + PageSize = 10 + }; + + _exceptionLogManagerMock?.Setup(x => x.GetExceptionLogs(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + var paging = new Paging(); + + //Act + var res = await _exceptionLogsController.Get(paging); + + //Assert + Assert.That(res, Is.Not.Null); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/CreateFormInstanceUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/CreateFormInstanceUnitTests.cs new file mode 100644 index 0000000..bbcf856 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/CreateFormInstanceUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class CreateFormInstanceUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + => await base.Setup(); + + [Test] + public async Task CreateFormInstance_NormanConditions_Returns200OkObjResult() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("320951a7-ba70-419f-8263-411aec720d59"), + Id = 5, + }; + + var formInstance = new CreateFormInstance(); + + var cancellationToken = CancellationToken.None; + + var newGeneralIdRef = new GeneralIdRef + { + Guid = new Guid("e8a8ca81-e7f6-4dc8-9610-d31a4345e331"), + Id = 2354, + }; + + _formsManagerMock!.Setup(x => x.CreateFormInstanceAsync(It.IsAny(), formInstance, cancellationToken)).ReturnsAsync(newGeneralIdRef); + + //Act + var res = await _formsController.CreateFormInstance(formInstance, cancellationToken); + + //Assert + _formsManagerMock!.Verify(x => x.CreateFormInstanceAsync(It.IsAny(), formInstance, cancellationToken), Times.Once); + + Assert.That(res.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = (OkObjectResult)res; + Assert.That(objectResult.Value, Is.EqualTo(newGeneralIdRef)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/CreateFormsTemplateUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/CreateFormsTemplateUnitTests.cs new file mode 100644 index 0000000..181fd5b --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/CreateFormsTemplateUnitTests.cs @@ -0,0 +1,83 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class CreateFormsTemplateUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + => await base.Setup(); + + + [Test] + public async Task CreateCustomField_WithPredifaindGuid_RetunrOK() + { + //Arrange + var formGuid = new Guid("ff738e5b-1cf4-4530-8543-280b22b7f38f"); + var formDefinition = "TestDef"; + var formName = "TestName"; + var createFormTemplat = new CreateFormTemplate + { + Definition = formDefinition, + Name = formName, + Guid = formGuid, + }; + + //Act + var res = await _formsController.CreateFormTemplate(createFormTemplat); + + //Assert + _formsManagerMock!.Verify(x => x.CreateFormTemplateAsync(It.IsAny(), It.Is(f => f.Name == formName && f.Definition == formDefinition && f.Guid == formGuid), It.IsAny())); + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public async Task CreateCustomfield_WithOutAPredifiandGuid_rturnsOk() + { + //Arrange + var formDefinition = "TestDef"; + var formName = "TestName"; + var createFormTemplat = new CreateFormTemplate + { + Definition = formDefinition, + Name = formName, + }; + + //Act + var res = await _formsController.CreateFormTemplate(createFormTemplat); + + //Assert + _formsManagerMock!.Verify(x => x.CreateFormTemplateAsync(It.IsAny(), It.Is(f => f.Name == formName && f.Definition == formDefinition && f.Guid == null), It.IsAny())); + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public void CreateCustomField_WithExistingGuid_ReturnsBadRequest() + { + //Arrange + var formGuid = new Guid("c218dd57-e641-4e82-9d2e-28e952360fdf"); + var formDefinition = "TestDef"; + var formName = "TestName"; + const string errorMesage = "Guid error"; + var createFormTemplat = new CreateFormTemplate + { + Definition = formDefinition, + Name = formName, + Guid = formGuid, + }; + _formsManagerMock?.Setup(x => x.CreateFormTemplateAsync(It.IsAny(), It.Is(x => x.Guid == formGuid), It.IsAny())).ThrowsAsync(new ExistsException(errorMesage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _formsController.CreateFormTemplate(createFormTemplat); + }); + } +} diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/DeleteFormTemplateUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/DeleteFormTemplateUnitTests.cs new file mode 100644 index 0000000..2185e8f --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/DeleteFormTemplateUnitTests.cs @@ -0,0 +1,57 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class DeleteFormTemplateUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + => await base.Setup(); + + [Test] + public async Task DeleteFormTemplate_NormanConditions_Returns200OkObjResult() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("320951a7-ba70-419f-8263-411aec720d59"), + Id = 5, + }; + _formsManagerMock?.Setup(x => x.DeleteFormTemplateAsync(It.IsAny(), generalIdRef, It.IsAny())).Returns(Task.CompletedTask); + + //Act + var res = await _formsController.DeleteForm(generalIdRef); + + //Assert + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public void DeleteFormTemplate_NotExistingId_ThrowsNotFoundException() + { + var idNum = 5; + var guid = new Guid("58cc87a3-8819-45b9-91b4-9e0589e83b84"); + const string errorMessage = "Id error"; + + var generalIdRef = new GeneralIdRef + { + Id = idNum, + Guid = guid + }; + + _formsManagerMock?.Setup(x => x.DeleteFormTemplateAsync(It.IsAny(), It.Is(x => x.Id == idNum && x.Guid == guid), It.IsAny())).ThrowsAsync(new NotFoundException(errorMessage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _formsController.DeleteForm(generalIdRef); + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/EditFormInstanceAsyncUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/EditFormInstanceAsyncUnitTests.cs new file mode 100644 index 0000000..161888f --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/EditFormInstanceAsyncUnitTests.cs @@ -0,0 +1,45 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class EditFormInstanceAsyncUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + => await base.Setup(); + + [Test] + public async Task CreateFormInstance_NormanConditions_Returns200OkObjResult() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("320951a7-ba70-419f-8263-411aec720d59"), + Id = 5, + }; + + var formInstance = new EditFormInstance(); + + var cancellationToken = CancellationToken.None; + + var newGeneralIdRef = new GeneralIdRef + { + Guid = new Guid("e8a8ca81-e7f6-4dc8-9610-d31a4345e331"), + Id = 2354, + }; + + //Act + var res = await _formsController.EditFormInstance(formInstance, cancellationToken); + + //Assert + _formsManagerMock!.Verify(x => x.EditFormInstanceAsync(It.IsAny(), formInstance, cancellationToken), Times.Once); + + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/EditFormTemplateUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/EditFormTemplateUnitTests.cs new file mode 100644 index 0000000..ebc65a8 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/EditFormTemplateUnitTests.cs @@ -0,0 +1,70 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class EditFormTemplateUnitTests : FormsControllerTestBase +{ + [SetUp] + public override Task Setup() + => base.Setup(); + + [Test] + public async Task EditFormTemplate_NormalConditions_ReturnsOkObjectResult() + { + //Arrange + var formGuid = new Guid("b8094034-0bf5-49b4-a691-a1875547ba63"); + var definition = "Definition"; + var name = "Name"; + + var editModel = new EditFormTemplate + { + Id = new GeneralIdRef + { + Id = 5, + Guid = formGuid + }, + Definition = definition, + Name = name, + }; + + //Act + var res = await _formsController.EditFormTempalate(editModel); + + //Assert + _formsManagerMock!.Verify(x => x.EditFormTemplateAsync(It.IsAny(), It.Is(f => f.Name == name && f.Definition == definition && f.Id.Guid == formGuid), It.IsAny())); + Assert.That(res.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public void EditFormTemplate_NonExistingGeneralIdRef_ThrowsNotFoundException() + { + //Arrange + var formGuid = new Guid("c758bc67-18c6-49ce-98e3-e19439bb7dbf"); + var id = 1; + var errorMessage = "Tessst Error"; + var genralId = new GeneralIdRef + { + Guid = formGuid, + Id = id + }; + var editForm = new EditFormTemplate + { + Id = genralId + }; + _formsManagerMock?.Setup(x => x.EditFormTemplateAsync(It.IsAny(), It.Is(f => f.Id.Guid == formGuid && f.Id.Id == id), It.IsAny())).ThrowsAsync(new NotFoundException(errorMessage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _formsController.EditFormTempalate(editForm); + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/FormsControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/FormsControllerTestBase.cs new file mode 100644 index 0000000..072cad4 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/FormsControllerTestBase.cs @@ -0,0 +1,48 @@ +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System.Security.Claims; +using e_suite.API.Common; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +public abstract class FormsControllerTestBase : TestBase +{ + protected FormsController _formsController = null!; + protected Mock? _formsManagerMock; + + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + protected const string BadRequestText = "Bad request"; + protected const string NotFoundText = "Not found"; + + public override async Task Setup() + { + await base.Setup(); + + _formsManagerMock = new Mock(); + + _formsController = new FormsController(_formsManagerMock.Object); + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _formsController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormInstanceUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormInstanceUnitTests.cs new file mode 100644 index 0000000..ef4c54c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormInstanceUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class GetFormInstanceUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + => await base.Setup(); + + [Test] + public async Task GetFormInstance_NormanConditions_Returns200OkObjResult() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("320951a7-ba70-419f-8263-411aec720d59"), + Id = 5, + }; + + var formInstance = new ReadFormInstance(); + + var cancellationToken = CancellationToken.None; + + _formsManagerMock!.Setup(x => x.GetFormInstanceAsync(generalIdRef, cancellationToken)).ReturnsAsync(formInstance); + + //Act + var res = await _formsController.GetFormInstance(generalIdRef, cancellationToken); + + //Assert + Assert.That(res.GetType(), Is.EqualTo(typeof(OkObjectResult))); + + var objectResult = (OkObjectResult)res; + Assert.That(objectResult.Value, Is.EqualTo(formInstance)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormTemplateUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormTemplateUnitTests.cs new file mode 100644 index 0000000..8354d32 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormTemplateUnitTests.cs @@ -0,0 +1,121 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class GetFormTemplateUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetFormTemplate_ByGuidOnly_ReturnsOk() + { + //Arrange + var formGuid = new Guid("c396663c-63ae-464b-9bd4-c5c90abf2b26"); + var formDefinition = "TestDef"; + var formName = "TestName"; + long id = 1; + var idRef = new GeneralIdRef + { + Guid = formGuid, + Id = null + }; + + var formObj = new GetFormTemplate + { + Definition = formDefinition, + Name = formName, + Id = id, + Guid = formGuid, + Version = 1 + }; + _formsManagerMock!.Setup(x => x.GetFormTemplateAsync(It.Is(f => f.Id == null && f.Guid == formGuid), It.IsAny())).ReturnsAsync(formObj); + + //Act + var res = await _formsController.GetFormTemplate(idRef); + + //Assert + var objectResult = res as OkObjectResult; + Assert.That(objectResult?.Value, Is.Not.Null); + if (objectResult?.Value is not null) + { + Assert.That(objectResult.Value.GetType(), Is.EqualTo(typeof(GetFormTemplate))); + var form = objectResult?.Value as GetFormTemplate; + Assert.That(form?.Name, Is.EqualTo(formName)); + Assert.That(form?.Definition, Is.EqualTo(formDefinition)); + Assert.That(form?.Guid, Is.EqualTo(formGuid)); + Assert.That(form?.Id, Is.EqualTo(id)); + } + } + + [Test] + public async Task GetFormTemplate_ByIdOnly_ReturnsOK() + { + //Arrange + var formGuid = new Guid("20d67e19-7551-4ebc-93f1-5f6d4df1dea8"); + var formDefinition = "TestDef"; + var formName = "TestName"; + long id = 1; + var idRef = new GeneralIdRef + { + Guid = null, + Id = id + }; + + var formObj = new GetFormTemplate + { + Definition = formDefinition, + Name = formName, + Id = id, + Guid = formGuid, + Version = 1 + }; + _formsManagerMock!.Setup(x => x.GetFormTemplateAsync(It.Is(f => f.Id == id && f.Guid == null), It.IsAny())).ReturnsAsync(formObj); + + //Act + var res = await _formsController.GetFormTemplate(idRef); + + //Assert + var objectResult = res as OkObjectResult; + Assert.That(objectResult?.Value, Is.Not.Null); + if (objectResult?.Value is not null) + { + Assert.That(objectResult.Value.GetType(), Is.EqualTo(typeof(GetFormTemplate))); + var form = objectResult?.Value as GetFormTemplate; + Assert.That(form?.Name, Is.EqualTo(formName)); + Assert.That(form?.Definition, Is.EqualTo(formDefinition)); + Assert.That(form?.Guid, Is.EqualTo(formGuid)); + Assert.That(form?.Id, Is.EqualTo(id)); + } + } + + [Test] + public void GetFormTemplate_UnexistingId_Returns404() + { + //Arrange + long id = 1; + const string errorMessage = "Guid error"; + var idRef = new GeneralIdRef + { + Guid = null, + Id = id + }; + _formsManagerMock?.Setup(x => x.GetFormTemplateAsync(It.IsAny(), It.IsAny())).ThrowsAsync(new NotFoundException(errorMessage)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var res = await _formsController.GetFormTemplate(idRef); + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormTemplatesUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormTemplatesUnitTests.cs new file mode 100644 index 0000000..9a041b1 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/FormsControllerUnitTests/GetFormTemplatesUnitTests.cs @@ -0,0 +1,83 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.FormsControllerUnitTests; + +[TestFixture] +public class GetFormTemplatesUnitTests : FormsControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetFormTemplates_NormalConditions_ReturnsOkObjResult() + { + //Arrange + var paginatedData = new PaginatedData + { + Count = 2, + Data = new List { new() }, + Page = 1, + PageSize = 10 + }; + + _formsManagerMock?.Setup(x => x.GetFormTemplatesAsync(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + var paging = new Paging(); + + //Act + var res = await _formsController.GetFormTemplates(paging); + + //Assert + Assert.That(res, Is.Not.Null); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + } + + [Test] + public async Task GetFormTemplates_NormalConditions_ReturnsExpectedObjects() + { + //Arrange + var formTemplateOne = new GetFormTemplate + { + Definition = "Test", + Name = "Name" + }; + var formTemplateTwo = new GetFormTemplate + { + Definition = "Test", + Name = "Name" + }; + var collection = new List { formTemplateOne, formTemplateTwo }; + + var paginatedData = new PaginatedData + { + Count = 2, + Data = collection, + Page = 1, + PageSize = 10 + }; + + _formsManagerMock?.Setup(x => x.GetFormTemplatesAsync(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + var paging = new Paging(); + + //Act + var res = await _formsController.GetFormTemplates(paging); + + //Assert + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = res as OkObjectResult; + Assert.That(objectResult?.Value, Is.Not.Null); + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType(), Is.EqualTo(typeof(PaginatedData))); + var formCollection = objectResult?.Value as PaginatedData; + Assert.That(formCollection?.Count, Is.EqualTo(2)); + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/DeleteUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/DeleteUnitTests.cs new file mode 100644 index 0000000..cdabb0c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/DeleteUnitTests.cs @@ -0,0 +1,36 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.GlossariesManagerControllerUnitTests; + +[TestFixture] +public class DeleteUnitTests : GlossariesManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + + + } + + [Test] + public async Task Delete_WhenCalled_ReturnsOK() + { + //Arrange + var glossaryItem = new GeneralIdRef(); + + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _glossariesController.Delete(glossaryItem, cancellationToken); + + //Assert + _glossariesManagerMock.Verify(x => x.DeleteGlossaryItem(It.IsAny(), glossaryItem, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/GetUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/GetUnitTests.cs new file mode 100644 index 0000000..5b6747a --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/GetUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.GlossariesManagerControllerUnitTests; + +[TestFixture] +public class GetUnitTests : GlossariesManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + [Test] + public async Task Get_WhenCalled_ReturnsOKResultWithData() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("f6bfa906-a4f6-41a0-bbad-06b77af8ac50") + }; + + var cancellationToken = CancellationToken.None; + + var glossaryItem = new GlossaryItem(); + _glossariesManagerMock.Setup(x => x.GetGlossaryItem(It.IsAny(), generalIdRef, cancellationToken)).ReturnsAsync(glossaryItem); + + //Act + var actualResult = await _glossariesController.Get(generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.EqualTo(glossaryItem)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/GlossariesManagerControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/GlossariesManagerControllerTestBase.cs new file mode 100644 index 0000000..c4dc338 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/GlossariesManagerControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.GlossariesManagerControllerUnitTests; + +public abstract class GlossariesManagerControllerTestBase : TestBase +{ + protected Mock _glossariesManagerMock = null!; + protected GlossariesController _glossariesController = null!; + + public override async Task Setup() + { + await base.Setup(); + _glossariesManagerMock = new Mock(); + _glossariesController = new GlossariesController(_glossariesManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _glossariesController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/PostUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/PostUnitTests.cs new file mode 100644 index 0000000..b610f19 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/PostUnitTests.cs @@ -0,0 +1,34 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.GlossariesManagerControllerUnitTests; + +[TestFixture] +public class PostUnitTests : GlossariesManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task Post_WhenCalled_ReturnsOK() + { + //Arrange + var newGlossaryItem = new NewGlossaryItem(); + + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _glossariesController.Post(newGlossaryItem, cancellationToken); + + //Assert + _glossariesManagerMock.Verify(x => x.AddGlossaryItem(It.IsAny(), newGlossaryItem, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/PutUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/PutUnitTests.cs new file mode 100644 index 0000000..034cb9a --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/GlossariesManagerControllerUnitTests/PutUnitTests.cs @@ -0,0 +1,34 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.GlossariesManagerControllerUnitTests; + +[TestFixture] +public class PutUnitTests : GlossariesManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task Put_WhenCalled_ReturnsOK() + { + //Arrange + var glossaryItem = new EditGlossaryItem(); + + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _glossariesController.Put(glossaryItem, cancellationToken); + + //Assert + _glossariesManagerMock.Verify(x => x.UpdateGlossaryItem(It.IsAny(), glossaryItem, cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/InternalMessagingControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/InternalMessagingControllerTestBase.cs new file mode 100644 index 0000000..ea97f64 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/InternalMessagingControllerTestBase.cs @@ -0,0 +1,51 @@ +using System.Security.Claims; +using e_suite.Messaging.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +public abstract class InternalMessagingControllerTestBase : TestBase +{ + protected Mock _sigmaImportMessageSenderMock = null!; + protected Mock _databaseMessageSenderMock = null!; + protected Mock _eFlowSyncMessageSenderMock = null!; + protected InternalMessagingController _internalMessagingController = null!; + + public override async Task Setup() + { + await base.Setup(); + + _sigmaImportMessageSenderMock = new Mock(); + _databaseMessageSenderMock = new Mock(); + _eFlowSyncMessageSenderMock = new Mock(); + + _internalMessagingController = + new InternalMessagingController(_sigmaImportMessageSenderMock.Object, _databaseMessageSenderMock.Object, _eFlowSyncMessageSenderMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity( + [ + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + ], "TestAuthentication")); + + _internalMessagingController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldEmailActionsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldEmailActionsUnitTests.cs new file mode 100644 index 0000000..2047da9 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldEmailActionsUnitTests.cs @@ -0,0 +1,26 @@ +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +[TestFixture] +public class PostClearOldEmailActionsUnitTests : InternalMessagingControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenCalled_CallsMessageSender() + { + //Arrange + + //Act + await _internalMessagingController.PostClearOldEmailActions(CancellationToken.None); + + //Assert + _databaseMessageSenderMock.Verify(x => x.PostClearOldEmailActions(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldPerformanceDataUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldPerformanceDataUnitTests.cs new file mode 100644 index 0000000..a0f0230 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldPerformanceDataUnitTests.cs @@ -0,0 +1,26 @@ +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +[TestFixture] +public class PostClearOldPerformanceDataUnitTests : InternalMessagingControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenCalled_CallsMessageSender() + { + //Arrange + + //Act + await _internalMessagingController.PostClearOldPerformanceData(CancellationToken.None); + + //Assert + _databaseMessageSenderMock.Verify(x => x.PostClearOldPerformanceData(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldSentinelDataUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldSentinelDataUnitTests.cs new file mode 100644 index 0000000..594429e --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldSentinelDataUnitTests.cs @@ -0,0 +1,26 @@ +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +[TestFixture] +public class PostClearOldSentinelDataUnitTests : InternalMessagingControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenCalled_CallsMessageSender() + { + //Arrange + + //Act + await _internalMessagingController.PostClearOldSentinelData(CancellationToken.None); + + //Assert + _databaseMessageSenderMock.Verify(x => x.PostClearOldSentinelData(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldSingleUserGuidsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldSingleUserGuidsUnitTests.cs new file mode 100644 index 0000000..0fed21d --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostClearOldSingleUserGuidsUnitTests.cs @@ -0,0 +1,26 @@ +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +[TestFixture] +public class PostClearOldSingleUserGuidsUnitTests : InternalMessagingControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenCalled_CallsMessageSender() + { + //Arrange + + //Act + await _internalMessagingController.PostClearOldSingleUserGuids(CancellationToken.None); + + //Assert + _databaseMessageSenderMock.Verify(x => x.PostClearOldSingleUserGuids(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostImportGmgProfilesUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostImportGmgProfilesUnitTests.cs new file mode 100644 index 0000000..8c24f07 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostImportGmgProfilesUnitTests.cs @@ -0,0 +1,26 @@ +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +[TestFixture] +public class PostImportGmgProfilesUnitTests : InternalMessagingControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenCalled_CallsMessageSender() + { + //Arrange + + //Act + await _internalMessagingController.PostImportGmgProfiles(CancellationToken.None); + + //Assert + _sigmaImportMessageSenderMock.Verify(x => x.PostImportGMGProfiles(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostImportPrintSpecificationsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostImportPrintSpecificationsUnitTests.cs new file mode 100644 index 0000000..8ecf17a --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/InternalMessagingControllerUnitTests/PostImportPrintSpecificationsUnitTests.cs @@ -0,0 +1,26 @@ +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.InternalMessagingControllerUnitTests; + +[TestFixture] +public class PostImportPrintSpecificationsUnitTests : InternalMessagingControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenCalled_CallsMessageSender() + { + //Arrange + + //Act + await _internalMessagingController.PostImportPrintSpecifications(CancellationToken.None); + + //Assert + _sigmaImportMessageSenderMock.Verify( x => x.PostImportPrintSpecifications(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/GetMailTemplateTypesUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/GetMailTemplateTypesUnitTests.cs new file mode 100644 index 0000000..3c84e31 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/GetMailTemplateTypesUnitTests.cs @@ -0,0 +1,55 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.Core.MailService; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.MailTemplatesControllerUnitTests; + +[TestFixture] +public class GetMailTemplateTypesUnitTests : MailTemplatesControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetMailTemplateTypes_WhenCalled_ReturnsPagedData() + { + //Arrange + var mailTemplateTypes = new List + { + new() + { + MailType = MailType.PasswordReset, + Description = "Password Reset" + } + }; + + var paginatedData = new PaginatedData + { + Count = mailTemplateTypes.Count, + Data = mailTemplateTypes, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + _mailTemplateManagerMock.Setup(x => x.GetMailTemplateTypes(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _mailTemplatesController.GetMailTemplateTypes(new Paging(), cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/GetMailTemplateUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/GetMailTemplateUnitTests.cs new file mode 100644 index 0000000..f84e999 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/GetMailTemplateUnitTests.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.models; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.MailTemplatesControllerUnitTests; + +[TestFixture] +public class GetMailTemplateUnitTests : MailTemplatesControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetMailTemplateTypes_WhenCalled_ReturnsPagedData() + { + //Arrange + var generalIdRef = new GeneralIdRef(); + + var mailType = MailType.PasswordReset; + + var cancellationToken = CancellationToken.None; + + var mailTemplate = new GetMailTemplate(); + + _mailTemplateManagerMock.Setup(x => x.GetMailTemplate(generalIdRef, mailType, cancellationToken)) + .ReturnsAsync(mailTemplate); + + //Act + var actualResult = await _mailTemplatesController.GetMailTemplate(generalIdRef, mailType, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult!.Value, Is.EqualTo(mailTemplate)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/MailTemplatesControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/MailTemplatesControllerTestBase.cs new file mode 100644 index 0000000..26fc05a --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/MailTemplatesControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.MailTemplatesControllerUnitTests; + +public abstract class MailTemplatesControllerTestBase : TestBase +{ + protected Mock _mailTemplateManagerMock = null!; + protected MailTemplatesController _mailTemplatesController = null!; + + public override async Task Setup() + { + await base.Setup(); + _mailTemplateManagerMock = new Mock(); + _mailTemplatesController = new MailTemplatesController(_mailTemplateManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity( + [ + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + ], "TestAuthentication")); + + _mailTemplatesController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/PostMailTemplateUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/PostMailTemplateUnitTests.cs new file mode 100644 index 0000000..d8530c2 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/MailTemplatesControllerUnitTests/PostMailTemplateUnitTests.cs @@ -0,0 +1,35 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.MailTemplatesControllerUnitTests; + +[TestFixture] +public class PostMailTemplateUnitTests : MailTemplatesControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetMailTemplateTypes_WhenCalled_ReturnsPagedData() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var mailTemplate = new PostMailTemplate(); + + //Act + var actualResult = await _mailTemplatesController.PostMailTemplate(mailTemplate, cancellationToken); + + //Assert + _mailTemplateManagerMock.Verify( + x => x.PostMailTemplate(mailTemplate, It.IsAny(), cancellationToken), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/MiscellaniousUnitTests/ControllerUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/MiscellaniousUnitTests/ControllerUnitTests.cs new file mode 100644 index 0000000..6b20e95 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/MiscellaniousUnitTests/ControllerUnitTests.cs @@ -0,0 +1,127 @@ +using System.Reflection; +using System.Text; +using eSuite.API.security; +using eSuite.API.Utilities; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Routing; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.MiscellaniousUnitTests; + +[TestFixture] +public class ControllerUnitTests +{ + private static IEnumerable GetAllControllers() + { + var referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies(); + var esuiteAPi = referencedAssemblies.Single(assembly => assembly.Name == "eSuite.API"); + var assembly = Assembly.Load(esuiteAPi); + + var controllers = assembly + .GetTypes() + .Where(type => typeof(ControllerBase).IsAssignableFrom(type) && !type.IsAbstract); + return controllers; + } + + private static CustomAttributeData? FindAttribute(MethodInfo publicMethod, Type type) + { + return publicMethod.CustomAttributes.FirstOrDefault(customAttribute => type.IsAssignableFrom(customAttribute.AttributeType)); + } + + private static bool ImplementsParameterByType(MethodInfo publicMethod, Type type) + { + return publicMethod.GetParameters().Any(parameter => type.IsAssignableFrom(parameter.ParameterType)); + } + + [Test] + public void Controller_Implemented_IsInheritedFromESuiteControllerBase() + { + //Arrange + var controllers = GetAllControllers(); + + Assert.That(controllers.Count(), Is.GreaterThan(0)); + + //Act + foreach (var controller in controllers) + if (!(typeof(ESuiteControllerBase).IsAssignableFrom(controller) || typeof(ESuiteController).IsAssignableFrom(controller))) + //Assert + Assert.Fail($"{controller.FullName} is not {typeof(ESuiteControllerBase)} or {typeof(ESuiteController)}"); + } + + [Test] + public void Controller_EveryMethod_ImplementsCancellationToken() + { + //Arrange + var controllers = GetAllControllers(); + + foreach (var controller in controllers) + { + var publicMethods = controller.GetMethods().Where(method => method.IsPublic).ToArray(); + + //Act + foreach (var publicMethod in publicMethods) + { + var attribute = FindAttribute(publicMethod, typeof(HttpMethodAttribute)); + if (attribute == null) + continue; + + if (!ImplementsParameterByType(publicMethod, typeof(CancellationToken))) + //Assert + Assert.Fail($"{controller.Name}.{publicMethod.Name} does not have a {typeof(CancellationToken)} parameter"); + } + + //Assert + Assert.That(publicMethods.Length, Is.GreaterThan(0)); + } + } + + [Test] + public void Controller_EveryMethod_HasAccessKeyAttribute() + { + //Arrange + var errors = new List(); + + var controllers = GetAllControllers(); + + foreach (var controller in controllers) + { + var publicMethods = controller.GetMethods().Where(method => method.IsPublic).ToArray(); + + //Act + foreach (var publicMethod in publicMethods) + { + var attribute = FindAttribute(publicMethod, typeof(HttpMethodAttribute)); + if (attribute == null) + continue; + + var accessKeyAttribute = FindAttribute(publicMethod, typeof(AccessKeyAttribute)); + if (accessKeyAttribute == null) + { + var allowAnonymousAttribute = FindAttribute(publicMethod, typeof(AllowAnonymousAttribute)); + if (allowAnonymousAttribute != null) + continue; + + errors.Add($"{controller.Name}.{publicMethod.Name} does not have an AccessKeyAttribute"); + } + } + + //Assert + Assert.That(publicMethods.Count, Is.GreaterThan(0)); + } + + Assert.Multiple(() => + { + if (errors.Count > 0) + { + var sb = new StringBuilder(); + foreach (var error in errors) + { + sb.AppendLine(error); + } + + Assert.Fail(sb.ToString()); + } + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/CreateOrganisationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/CreateOrganisationUnitTests.cs new file mode 100644 index 0000000..179da80 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/CreateOrganisationUnitTests.cs @@ -0,0 +1,66 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.OrganisationControllerUnitTests; + +[TestFixture] +public class CreateOrganisationUnitTests : OrganisationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ShouldReturnBadRequest() + { + //Arrange + const string execptionText = "Guid is already used."; + + var organisation = new CreateOrganisation + { + Guid = new Guid("f14056df-94d3-42cc-9a03-5da516477d63"), + Name = "Sun-Strategy", + Address = "Bristol, UK", + Status = OrganisationStatus.Active + }; + + _organisationManagerMock.Setup(x => x.AddOrganisation(It.IsAny(), organisation, true, It.IsAny())).Throws(new ArgumentException(execptionText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _organisationController.CreateOrganisation(organisation); + }); + } + + [Test] + public async Task CreateOrganisation_EverythingCorrect_CreatesOrganisation() + { + //Arrange + var organisation = new CreateOrganisation + { + Guid = new Guid("34f241fa-5289-4fc5-a5e9-065d594238c2"), + Name = "Sun-Strategy", + Address = "Bristol, UK", + Status = OrganisationStatus.Active + }; + + //Act + var actualResult = await _organisationController.CreateOrganisation(organisation); + + //Assert + _organisationManagerMock.Verify(x => x.AddOrganisation(It.IsAny(), organisation, true,It.IsAny()), Times.Once()); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/DeleteOrganisationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/DeleteOrganisationUnitTests.cs new file mode 100644 index 0000000..a376960 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/DeleteOrganisationUnitTests.cs @@ -0,0 +1,60 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.OrganisationControllerUnitTests; + +[TestFixture] +public class DeleteOrganisationUnitTests : OrganisationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ShouldReturnBadRequest() + { + //Arrange + var exceptionText = "Organisation with this id does not exist."; + + var organisationId = new GeneralIdRef + { + Guid = new Guid("b793674e-e798-4f26-8c16-fdfc94c95194") + }; + + _organisationManagerMock.Setup(x => x.DeleteOrganisation(It.IsAny(), organisationId, true, It.IsAny())).Throws(new NotFoundException(exceptionText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _organisationController.DeleteOrganisation(organisationId); + }); + } + + [Test] + public async Task DeleteOrganisation_WhenCalledWithGoodParameters_ReturnsCalledModuleAndReturnsOK() + { + //Arrange + var organisationId = new GeneralIdRef + { + Guid = new Guid("3e8965fa-7a35-429a-95be-10fd47cae43b") + }; + + //Act + var actualResult = await _organisationController.DeleteOrganisation(organisationId); + + //Assert + _organisationManagerMock.Verify(x => x.DeleteOrganisation(It.IsAny(), organisationId, true, It.IsAny()), Times.Once()); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/EditOrganisationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/EditOrganisationUnitTests.cs new file mode 100644 index 0000000..5c73c24 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/EditOrganisationUnitTests.cs @@ -0,0 +1,73 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.OrganisationControllerUnitTests; + +[TestFixture] +public class EditOrganisationUnitTests : OrganisationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ShouldReturnNotFound() + { + //Arrange + var exceptionText = "Organisation with this id does not exist."; + + var organisation = new EditOrganisation + { + GeneralIdRef = new GeneralIdRef + { + Guid = new Guid("c0504bf6-b8b9-4a64-89ef-06b04e9e8d12") + }, + Name = "Sun-Strategy", + Address = "Bristol, UK", + Status = OrganisationStatus.Active + }; + + _organisationManagerMock.Setup(x => x.EditOrganisation(It.IsAny(), organisation, true, It.IsAny())).Throws(new NotFoundException(exceptionText)); + + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _organisationController.EditOrganisation(organisation); + }); + } + + [Test] + public async Task ShouldReturnOk() + { + //Arrange + var organisation = new EditOrganisation + { + GeneralIdRef = new GeneralIdRef + { + Guid = new Guid("2777ed7e-294f-4b54-9e06-ebdb3facebe1") + }, + Name = "Sun-Strategy", + Address = "Bristol, UK", + Status = OrganisationStatus.Active + }; + + //Act + var actualResult = await _organisationController.EditOrganisation(organisation); + + //Assert + _organisationManagerMock.Verify(x => x.EditOrganisation(It.IsAny(), organisation, true, It.IsAny()), Times.Once()); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/GetOrganisationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/GetOrganisationUnitTests.cs new file mode 100644 index 0000000..3b28b04 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/GetOrganisationUnitTests.cs @@ -0,0 +1,75 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.OrganisationControllerUnitTests; + +[TestFixture] +public class GetOrganisationUnitTests : OrganisationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ShouldReturnOk() + { + //Arrange + var organisationGeneralIdRef = new GeneralIdRef + { + Guid = new Guid("22676f28-b9dd-4961-b499-e35de117617c"), + Id = 999, + }; + + var organisation = new Organisation + { + Id = (long)organisationGeneralIdRef.Id, + Guid = (Guid)organisationGeneralIdRef.Guid, + Name = "Sun-Strategy", + Address = "Bristol, UK", + Status = OrganisationStatus.Active, + Deleted = false, + }; + + _organisationManagerMock.Setup(x => x.GetOrganisation(It.IsAny(), It.IsAny())).ReturnsAsync(organisation); + + //Act + var actualResult = await _organisationController.GetOrganisation(organisationGeneralIdRef); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(Organisation))); + } + + [Test] + public void ShouldReturnNotFound() + { + //Arrange + var exceptionText = "Organisation with this id does not exist."; + + var organisationGeneralIdRef = new GeneralIdRef + { + Guid = new Guid("1d0dcee0-469c-4deb-9a68-f6ff0c9b79a6"), + Id = 999, + }; + + _organisationManagerMock.Setup(x => x.GetOrganisation(It.IsAny(), It.IsAny())).ThrowsAsync(new NotFoundException(exceptionText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _organisationController.GetOrganisation(organisationGeneralIdRef); + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/GetOrganisationsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/GetOrganisationsUnitTests.cs new file mode 100644 index 0000000..ea03b16 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/GetOrganisationsUnitTests.cs @@ -0,0 +1,59 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.OrganisationControllerUnitTests; + +[TestFixture] +public class GetOrganisationsUnitTests : OrganisationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ShouldReturnOk() + { + //Arrange + var organisations = new List + { + new() + { + Id = 999, + Guid = new Guid("d6e5d3e2-d154-4e04-af93-14d2c85e2a86"), + Name = "Sun-Strategy", + }, + new() + { + Id = 888, + Guid = new Guid("c8329e94-426a-4d65-84e5-93aa1cf54063"), + Name = "Amdaris", + }, + }; + + var paginatedData = new PaginatedData + { + Count = organisations.Count, + Data = organisations, + Page = 1, + PageSize = 10 + }; + + _organisationManagerMock.Setup(x => x.GetOrganisationList(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _organisationController.GetOrganisationsList(new Paging(), CancellationToken.None); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/OrganisationControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/OrganisationControllerTestBase.cs new file mode 100644 index 0000000..627a46d --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/OrganisationControllerUnitTests/OrganisationControllerTestBase.cs @@ -0,0 +1,44 @@ +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System.Security.Claims; +using e_suite.API.Common; + +namespace eSuite.API.UnitTests.Controllers.OrganisationControllerUnitTests; + +public abstract class OrganisationControllerTestBase : TestBase +{ + protected Mock _organisationManagerMock = null!; + protected OrganisationsController _organisationController = null!; + + public override async Task Setup() + { + await base.Setup(); + _organisationManagerMock = new Mock(); + _organisationController = new OrganisationsController(_organisationManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Test Test"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _organisationController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/EditMyProfileUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/EditMyProfileUnitTests.cs new file mode 100644 index 0000000..92fecc2 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/EditMyProfileUnitTests.cs @@ -0,0 +1,71 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.ProfileControllerUnitTests; + +[TestFixture] +public class EditMyProfileUnitTests : ProfileControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditMyProfile_EmailExistsExists_ReturnsBadRequest() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + const string errorText = "Test error message"; + + AddAuthorisedUserToController(id, email, displayName); + + var userProfile = new UpdatedUserProfile + { + Email = "duplicate@test.test" + }; + + _userManagerMock.Setup(x => x.UpdateProfile(It.IsAny(), email, userProfile, It.IsAny())).Throws(new ExistsException(errorText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _profileController.EditMyProfile(userProfile); + }); + } + + [Test] + public async Task EditMyProfile_EverythingOk_ReturnsOk() + { + //Arrange + const long Id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(Id, email, displayName); + + var userProfile = new UpdatedUserProfile + { + Email = "newemail@test.test" + }; + + //Act + var actualResult = await _profileController.EditMyProfile(userProfile); + + //Assert + _userManagerMock.Verify(x => x.UpdateProfile(It.IsAny(), email, userProfile, It.IsAny()), Times.Once()); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/GetMyProfileUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/GetMyProfileUnitTests.cs new file mode 100644 index 0000000..a2f24b4 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/GetMyProfileUnitTests.cs @@ -0,0 +1,87 @@ +using e_suite.API.Common.models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.ProfileControllerUnitTests; + +[TestFixture] +public class GetMyProfileUnitTests : ProfileControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetMyProfile_UserNotFound_Returns404() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + + var userProfile = new UserProfile + { + Email = email + }; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())).Returns(Task.FromResult(userProfile)); + + //Act + var actualResult = await _profileController.GetMyProfile(); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(UserProfile))); + + var problemDetails = objectResult.Value as UserProfile; + + Assert.That(problemDetails?.Email, Is.EqualTo(userProfile.Email)); + } + } + + [Test] + public async Task GetMyProfile_UserExists_ReturnsProfile() + { + //Arrange + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + + UserProfile? userProfile = null; + + _userManagerMock.Setup(x => x.GetProfile(email, It.IsAny())).Returns(Task.FromResult(userProfile)!); + + //Act + var actualResult = await _profileController.GetMyProfile(); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Null); + + if (objectResult?.Value != null) + { + Assert.That(objectResult.Value.GetType, Is.EqualTo(typeof(UserProfile))); + + var problemDetails = objectResult.Value as UserProfile; + + Assert.That(problemDetails?.Email, Is.EqualTo(userProfile?.Email)); + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/ProfileControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/ProfileControllerTestBase.cs new file mode 100644 index 0000000..f17b224 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/ProfileControllerUnitTests/ProfileControllerTestBase.cs @@ -0,0 +1,45 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.ProfileControllerUnitTests; + +public abstract class ProfileControllerTestBase : TestBase +{ + protected ProfileController _profileController = null!; + protected Mock _userManagerMock = null!; + + protected const string AccessDeniedText = "Access denied"; + protected const string BadRequestText = "Bad request"; + protected const string NotFoundText = "Not found"; + protected const string LoginAcceptedText = "Login accepted"; + + public override async Task Setup() + { + await base.Setup(); + + _userManagerMock = new Mock(); + + _profileController = new ProfileController(_userManagerMock.Object); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _profileController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/AddRoleUserUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/AddRoleUserUnitTests.cs new file mode 100644 index 0000000..2400e77 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/AddRoleUserUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class AddRoleUserUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task AddRoleUser_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var userRoleIds = new UserRoleIds(); + + //Act + var actualResult = await _roleController.AddRoleUser(userRoleIds, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.AddRoleUser(It.IsAny(), userRoleIds, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/CreateRoleUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/CreateRoleUnitTests.cs new file mode 100644 index 0000000..8f947e2 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/CreateRoleUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class CreateRoleUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateRole_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var createRole = new CreateRole(); + + //Act + var actualResult = await _roleController.CreateRole(createRole, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.CreateRole(It.IsAny(), createRole, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleAccessUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleAccessUnitTests.cs new file mode 100644 index 0000000..607a3d5 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleAccessUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class DeleteRoleAccessUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task PostRoleAccess_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var access = new DeleteRoleSecurityAccess(); + + //Act + var actualResult = await _roleController.DeleteRoleAccess(access, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.DeleteRoleSecurityAccess(It.IsAny(), access, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleUnitTests.cs new file mode 100644 index 0000000..6d1fd21 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class DeleteRoleUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteRole_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var deleteRole = new GeneralIdRef(); + + //Act + var actualResult = await _roleController.DeleteRole(deleteRole, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.DeleteRole(It.IsAny(), deleteRole, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleUserUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleUserUnitTests.cs new file mode 100644 index 0000000..cf7a099 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/DeleteRoleUserUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class DeleteRoleUserUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteRoleUser_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var userRoleIds = new UserRoleIds(); + + //Act + var actualResult = await _roleController.DeleteRoleUser(userRoleIds, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.DeleteRoleUser(It.IsAny(), userRoleIds, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/EditRoleUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/EditRoleUnitTests.cs new file mode 100644 index 0000000..6362016 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/EditRoleUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class EditRoleUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditRole_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var editRole = new EditRole(); + + //Act + var actualResult = await _roleController.EditRole(editRole, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.EditRole(It.IsAny(), editRole, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetAccessListUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetAccessListUnitTests.cs new file mode 100644 index 0000000..ab18aab --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetAccessListUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class GetAccessListUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetAccessList_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List(); + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + _roleManagerMock.Setup(x => x.GetAccessList(paging, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _roleController.GetAccessList(paging, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleAccessUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleAccessUnitTests.cs new file mode 100644 index 0000000..fc034c4 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleAccessUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class GetRoleAccessUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetRoleAccess_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List(); + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + _roleManagerMock.Setup(x => x.GetRoleAccess(paging, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _roleController.GetRoleAccess(paging, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleUnitTests.cs new file mode 100644 index 0000000..ee93175 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleUnitTests.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class GetRoleUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetDomains_WhenCalled_ReturnsPagedData() + { + //Arrange + var role = new ReadRole + { + Guid = new Guid("35aad917-131a-4b67-9a0c-c1b1ff519bec"), + Id = 564, + Name = "Some Role" + }; + + var cancellationToken = CancellationToken.None; + var generalIdRef = new GeneralIdRef(); + + _roleManagerMock.Setup(x => x.GetRole(It.IsAny(), cancellationToken)).ReturnsAsync(role); + + //Act + var actualResult = await _roleController.GetRole(generalIdRef.Id, generalIdRef.Guid, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.EqualTo(role)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleUsersUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleUsersUnitTests.cs new file mode 100644 index 0000000..9804cd6 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRoleUsersUnitTests.cs @@ -0,0 +1,60 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class GetRoleUsersUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetRoleUsers_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List + { + new() + { + Guid = new Guid("914d36c6-0572-4e48-9c85-639b4d1cd8c8"), + Id = 6574, + DisplayName = "TestyMcTester" + } + }; + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + var generalIdRef = new GeneralIdRef(); + + _roleManagerMock.Setup(x => x.GetRoleUsers(paging, generalIdRef, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _roleController.GetRoleUsers(paging, generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRolesUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRolesUnitTests.cs new file mode 100644 index 0000000..927bcc8 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/GetRolesUnitTests.cs @@ -0,0 +1,60 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class GetRolesUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetRoles_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List + { + new() + { + Guid = new Guid("16241e96-9062-4221-b073-a48330b2cc9b"), + Id = 999, + Name = "Some Role" + } + }; + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + var generalIdRef = new GeneralIdRef(); + + _roleManagerMock.Setup(x => x.GetRoles(paging, generalIdRef, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _roleController.GetRoles(paging, generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/PostRoleAccessUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/PostRoleAccessUnitTests.cs new file mode 100644 index 0000000..591a42a --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/PostRoleAccessUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +[TestFixture] +public class PostRoleAccessUnitTests : RoleControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task PostRoleAccess_WhenCalled_ReturnsOK() + { + //Arrange + var cancellationToken = CancellationToken.None; + var access = new AddRoleSecurityAccess(); + + //Act + var actualResult = await _roleController.PostRoleAccess(access, cancellationToken); + + //Assert + _roleManagerMock.Verify(x => x.AddRoleSecurityAccess(It.IsAny(), access, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/RoleControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/RoleControllerTestBase.cs new file mode 100644 index 0000000..143df10 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/RoleControllerUnitTests/RoleControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.RoleControllerUnitTests; + +public abstract class RoleControllerTestBase : TestBase +{ + protected Mock _roleManagerMock = null!; + protected RoleController _roleController = null!; + + public override async Task Setup() + { + await base.Setup(); + _roleManagerMock = new Mock(); + _roleController = new RoleController(_roleManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _roleController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/CreateSequenceUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/CreateSequenceUnitTests.cs new file mode 100644 index 0000000..7f7d50f --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/CreateSequenceUnitTests.cs @@ -0,0 +1,74 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Sequences; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +[TestFixture] +public class CreateSequenceUnitTests : SequenceControllerBaseTest +{ + + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CreateSequence_WhenSequenceExists_ThrowsExistsException() + { + //Arrange + const string errorText = "A sequence with this name already exists"; + + var guid = new Guid("2fb9cb23-ca52-44b5-a7a5-74a5f449fa47"); + var sequence = new NewSequence + { + Guid = guid, + Name = $"sequence-{guid}", + Pattern = "orders", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + _sequenceManagerMock.Setup(x => x.CreateSequence(It.IsAny(), sequence, It.IsAny())).Throws(new ExistsException(errorText)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _sequenceController.CreateSequence(sequence); + }); + } + + [Test] + public async Task CreateSequence_SequenceDoesNotExist_ReturnsOK() + { + //Arrange + var guid = new Guid("5fa0cd73-3cb8-4ee8-9827-1e5cd78c4aa9"); + var sequence = new NewSequence + { + Guid = guid, + Name = $"sequence-{guid}", + Pattern = "orders", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + //Act + var actualResult = await _sequenceController.CreateSequence(sequence); + + //Assert + _sequenceManagerMock.Verify(x => x.CreateSequence(It.IsAny(), sequence, It.IsAny()), Times.Once()); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/DeleteSequenceUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/DeleteSequenceUnitTests.cs new file mode 100644 index 0000000..63faf83 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/DeleteSequenceUnitTests.cs @@ -0,0 +1,72 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +[TestFixture] +public class DeleteSequenceUnitTests : SequenceControllerBaseTest +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteSequence_WhenNotFound_ThrowsException() + { + // Arrange + const string errorText = "Sequence not found."; + + var guid = new Guid("6461d22e-9abc-4563-8d30-cb6298cf2e10"); + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = guid }, + Name = $"sequence-{guid}", + Pattern = "[0]", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + _sequenceManagerMock.Setup(x => x.DeleteSequence(It.IsAny(), sequence.GeneralIdRef, It.IsAny())).Throws(new NotFoundException(errorText)); + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + var actualResult = await _sequenceController.DeleteSequence(sequence.GeneralIdRef); + }); + } + + [Test] + public async Task DeleteSequence_WhenSequenceDeleted_ReturnsOK() + { + // Arrange + var guid = new Guid("e88dc220-bdb6-4915-a31a-ad35ecbd1c83"); + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = guid }, + Name = $"sequence-{guid}", + Pattern = "[0]", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + // Act + var actualResult = await _sequenceController.DeleteSequence(sequence.GeneralIdRef); + + // Assert + _sequenceManagerMock.Verify(x => x.DeleteSequence(It.IsAny(), sequence.GeneralIdRef, It.IsAny()), Times.Once()); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/EditSequenceUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/EditSequenceUnitTests.cs new file mode 100644 index 0000000..6810b87 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/EditSequenceUnitTests.cs @@ -0,0 +1,100 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +[TestFixture] +public class EditSequenceUnitTests : SequenceControllerBaseTest +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditSequence_WhenNewSequenceNameAlreadyExists_ThrowsExistsException() + { + // Arrange + const string errorText = "A sequence with this name already exists"; + + var guid = new Guid("cdc17205-17ba-473b-87aa-c91509338d97"); + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = guid }, + Name = $"sequence-{guid}", + Pattern = "[0]", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + _sequenceManagerMock.Setup(x => x.EditSequence(It.IsAny(), sequence, It.IsAny())).Throws(new ExistsException(errorText)); + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + var actualResult = await _sequenceController.EditSequence(sequence); + }); + } + + [Test] + public void EditSequence_SequenceNotFound_ThrowsNotFoundException() + { + // Arrange + const string errorText = "Sequence not found."; + + var guid = new Guid("62cb2b8f-85ed-4c3a-a986-797270cfca57"); + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = guid }, + Name = $"sequence-{guid}", + Pattern = "[0]", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + + _sequenceManagerMock.Setup(x => x.EditSequence(It.IsAny(), sequence, It.IsAny())).Throws(new NotFoundException(errorText)); + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + var actualResult = await _sequenceController.EditSequence(sequence); + }); + } + + [Test] + public async Task EditSequence_WhenSequenceFound_ReturnsOK() + { + // Arrange + var guid = new Guid("00339b4d-4ce8-4097-8b34-b645164c9926"); + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = guid }, + Name = $"sequence-{guid}", + Pattern = "[0]", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + // Act + var actualResult = await _sequenceController.EditSequence(sequence); + + // Assert + _sequenceManagerMock.Verify(x => x.EditSequence(It.IsAny(), sequence, It.IsAny()), Times.Once()); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + var objectResult = actualResult as OkResult; + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/GetSequenceUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/GetSequenceUnitTests.cs new file mode 100644 index 0000000..e20abb6 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/GetSequenceUnitTests.cs @@ -0,0 +1,56 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +[TestFixture] +public class GetSequenceUnitTests : SequenceControllerBaseTest +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetSequence_SequenceNotFound_ReturnsNotFoundResult() + { + //Arrange + var generalIdRef = new GeneralIdRef(); + + _sequenceManagerMock.Setup(x => x.GetSequence(It.IsAny(), It.IsAny())) + .Throws(new NotFoundException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _sequenceController.GetSequence(generalIdRef.Id, generalIdRef.Guid); + }); + } + + + [Test] + public async Task GetSequence_SequenceFound_ReturnsOk() + { + //Arrange + var generalIdRef = new GeneralIdRef(); + + var expectedResult = new Sequence(); + + _sequenceManagerMock.Setup(x => x.GetSequence(It.IsAny(), It.IsAny())).ReturnsAsync(expectedResult); + + //Act + var actualResult = await _sequenceController.GetSequence(generalIdRef.Id, generalIdRef.Guid); + + //Assert + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.EqualTo(expectedResult)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/NextValueUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/NextValueUnitTests.cs new file mode 100644 index 0000000..29c3033 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/NextValueUnitTests.cs @@ -0,0 +1,64 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.API.Models; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +[TestFixture] +public class NextValueUnitTests : SequenceControllerBaseTest +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task NextValue_Called_IssuesNextValueAndReturnsOK() + { + // Arrange + var responses = new List { "Order 001 from 12/10/2022" }; + + var guid = new Guid("fbe77372-0f7e-4a93-ad8e-11426ea1562e"); + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef + { + Guid = guid + }, + Name = $"sequence-{guid}", + Pattern = "Order [000] from {DD}/{MM}/{YYYY}", + Increment = 1, + RolloverType = Rollover.Continuous, + Seed = 0 + }; + + _sequenceManagerMock.Setup(x => x.NextValue(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(responses); + + _sequenceManagerMock.Setup(x => x.NextValue(It.IsAny(), It.IsAny(), 1, It.IsAny())).ReturnsAsync(responses); + + // Act + var generalId = new GeneralIdRef { Guid = sequence.GeneralIdRef.Guid }; + + var sequenceIssueRequest = new SequenceIssueRequest + { + GeneralIdRef = generalId, + Count = 1 + }; + + var actualResult = await _sequenceController.NextValue(sequenceIssueRequest); + + // Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + + var objectResult = actualResult as OkObjectResult; + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(List))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/ReadSequencesUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/ReadSequencesUnitTests.cs new file mode 100644 index 0000000..d4ebc84 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/ReadSequencesUnitTests.cs @@ -0,0 +1,74 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using MockQueryable; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +[TestFixture] +public class ReadSequencesUnitTests : SequenceControllerBaseTest +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ShouldReturnOk() + { + // Arrange + var sequences = new List { + new() + { + Guid = new Guid("001ca58e-6738-4a24-9114-c9d7d515fac1"), + Id = 1, + Name = "First sequence" + }, + new() + { + Guid = new Guid("4bfc0d4c-4c39-4513-a9d0-d70d3de3c4a9"), + Id = 2, + Name = "Second sequence" + }, + new() + { + Guid = new Guid("3f816357-dc8e-4a1e-aa5d-3bd5b0c60ffe"), + Id = 3, + Name = "Third sequence" + } + }.BuildMock(); + + var paginatedData = new PaginatedData + { + Count = sequences.Count(), + Page = 1, + PageSize = 10, + Data = sequences + }; + + _sequenceManagerMock.Setup(x => x.GetSequences(It.IsAny(), It.IsAny())).ReturnsAsync(paginatedData); + var paging = new Paging(); + + // Act + var actualResult = await _sequenceController.GetSequences(paging); + + // Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + + var objectResult = actualResult as OkObjectResult; + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + + var listResult = objectResult.Value as PaginatedData; + Assert.That(listResult, Is.Not.Null); + Assert.That(listResult!.Count, Is.EqualTo(3)); + Assert.That(listResult!.Page, Is.EqualTo(1)); + Assert.That(listResult!.PageSize, Is.EqualTo(10)); + Assert.That(listResult!.TotalPages, Is.EqualTo(1)); + Assert.That(listResult!.Data.Count, Is.EqualTo(3)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/SequenceControllerBaseTest.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/SequenceControllerBaseTest.cs new file mode 100644 index 0000000..7a7ea16 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SequenceManagerControllerUnitTests/SequenceControllerBaseTest.cs @@ -0,0 +1,44 @@ +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System.Security.Claims; +using e_suite.API.Common; + + +namespace eSuite.API.UnitTests.Controllers.SequenceManagerControllerUnitTests; + +public abstract class SequenceControllerBaseTest : TestBase +{ + protected Mock _sequenceManagerMock = null!; + protected SequencesController _sequenceController = null!; + + public override async Task Setup() + { + await base.Setup(); + _sequenceManagerMock = new Mock(); + _sequenceController = new SequencesController(_sequenceManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Test Test"; + + AddAuthorisedUserToController(id, email, displayName); + } + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _sequenceController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/CreateSiteUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/CreateSiteUnitTests.cs new file mode 100644 index 0000000..fa0deb4 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/CreateSiteUnitTests.cs @@ -0,0 +1,35 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SiteControllerUnitTests; + +[TestFixture] +public class CreateSiteUnitTests : SiteControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSite_WhenCalled_ReturnsPagedData() + { + //Arrange + + + var cancellationToken = CancellationToken.None; + + var site = new CreateSite(); + + //Act + var actualResult = await _siteController.CreateSite(site, cancellationToken); + + //Assert + _siteManagerMock.Verify(x => x.CreateSite(It.IsAny(), site, true, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/DeleteSiteUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/DeleteSiteUnitTests.cs new file mode 100644 index 0000000..bfd1aad --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/DeleteSiteUnitTests.cs @@ -0,0 +1,33 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SiteControllerUnitTests; + +[TestFixture] +public class DeleteSiteUnitTests : SiteControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteSite_WhenCalled_ReturnsPagedData() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var site = new GeneralIdRef(); + + //Act + var actualResult = await _siteController.DeleteSite(site, cancellationToken); + + //Assert + _siteManagerMock.Verify(x => x.DeleteSite(It.IsAny(), site, true, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/EditSiteUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/EditSiteUnitTests.cs new file mode 100644 index 0000000..fc3126c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/EditSiteUnitTests.cs @@ -0,0 +1,33 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SiteControllerUnitTests; + +[TestFixture] +public class EditSiteUnitTests : SiteControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSite_WhenCalled_ReturnsPagedData() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var site = new EditSite(); + + //Act + var actualResult = await _siteController.EditSite(site, cancellationToken); + + //Assert + _siteManagerMock.Verify(x => x.EditSite(It.IsAny(), site, true, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/GetSiteUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/GetSiteUnitTests.cs new file mode 100644 index 0000000..3094879 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/GetSiteUnitTests.cs @@ -0,0 +1,40 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SiteControllerUnitTests; + +[TestFixture] +public class GetSiteUnitTests : SiteControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSite_WhenCalled_ReturnsPagedData() + { + //Arrange + var site = new ReadSite(); + + var cancellationToken = CancellationToken.None; + + var generalIdRef = new GeneralIdRef(); + + _siteManagerMock.Setup(x => x.GetSite(generalIdRef, cancellationToken)).ReturnsAsync(site); + + //Act + var actualResult = await _siteController.GetSite(generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.EqualTo(site)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/GetSitesUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/GetSitesUnitTests.cs new file mode 100644 index 0000000..b6fd9f0 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/GetSitesUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SiteControllerUnitTests; + +[TestFixture] +public class GetSitesUnitTests : SiteControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSites_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List(); + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + _siteManagerMock.Setup(x => x.GetSites(paging, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _siteController.GetSites(paging, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/SiteControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/SiteControllerTestBase.cs new file mode 100644 index 0000000..018d546 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SiteControllerUnitTests/SiteControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.SiteControllerUnitTests; + +public abstract class SiteControllerTestBase : TestBase +{ + protected Mock _siteManagerMock = null!; + protected SiteController _siteController = null!; + + public override async Task Setup() + { + await base.Setup(); + _siteManagerMock = new Mock(); + _siteController = new SiteController(_siteManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _siteController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/CreateSpecificationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/CreateSpecificationUnitTests.cs new file mode 100644 index 0000000..f5b482e --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/CreateSpecificationUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +[TestFixture] +public class CreateSpecificationUnitTests : SpecificationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSpecification_WhenCalled_ReturnsPagedData() + { + //Arrange + var cancellationToken = CancellationToken.None; + var createSpecification = new CreateSpecification(); + + //Act + var actualResult = await _specificationController.CreateSpecification(createSpecification, cancellationToken); + + //Assert + _specificationManagerMock.Verify(x => x.CreateSpecification(It.IsAny(), createSpecification, true, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/DeleteSpecificationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/DeleteSpecificationUnitTests.cs new file mode 100644 index 0000000..a5f2e96 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/DeleteSpecificationUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +[TestFixture] +public class DeleteSpecificationUnitTests : SpecificationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteSpecification_WhenCalled_ReturnsPagedData() + { + //Arrange + var cancellationToken = CancellationToken.None; + var generalIdRef = new GeneralIdRef(); + + //Act + var actualResult = await _specificationController.DeleteSpecification(generalIdRef, cancellationToken); + + //Assert + _specificationManagerMock.Verify(x => x.DeleteSpecification(It.IsAny(), generalIdRef, true, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/EditSpecificationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/EditSpecificationUnitTests.cs new file mode 100644 index 0000000..aeddaf5 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/EditSpecificationUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +[TestFixture] +public class EditSpecificationUnitTests : SpecificationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditSpecification_WhenCalled_ReturnsPagedData() + { + //Arrange + var cancellationToken = CancellationToken.None; + var editSpecification = new EditSpecification(); + + //Act + var actualResult = await _specificationController.EditSpecification(editSpecification, cancellationToken); + + //Assert + _specificationManagerMock.Verify(x => x.EditSpecification(It.IsAny(), editSpecification, true, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetSpecificationUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetSpecificationUnitTests.cs new file mode 100644 index 0000000..d10ce31 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetSpecificationUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +[TestFixture] +public class GetSpecificationUnitTests : SpecificationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSpecification_WhenCalled_ReturnsPagedData() + { + //Arrange + var specification = new ReadSpecification(); + + + var cancellationToken = CancellationToken.None; + var generalIdRef = new GeneralIdRef(); + + _specificationManagerMock.Setup(x => x.GetSpecification(generalIdRef, cancellationToken)).ReturnsAsync(specification); + + //Act + var actualResult = await _specificationController.GetSpecification(generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(ReadSpecification))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetSpecificationsUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetSpecificationsUnitTests.cs new file mode 100644 index 0000000..72302c0 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetSpecificationsUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +[TestFixture] +public class GetSpecificationsUnitTests : SpecificationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSpecifications_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List(); + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + _specificationManagerMock.Setup(x => x.GetSpecifications(paging, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _specificationController.GetSpecifications(paging, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetTemplateForPrintSpecUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetTemplateForPrintSpecUnitTests.cs new file mode 100644 index 0000000..5be1248 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/GetTemplateForPrintSpecUnitTests.cs @@ -0,0 +1,40 @@ +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +[TestFixture] +public class GetTemplateForPrintSpecUnitTests : SpecificationControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetTemplateForPrintSpec_WhenCalled_ReturnsPagedData() + { + //Arrange + var templateGeneralIdRef = new GeneralIdRef(); + + + var cancellationToken = CancellationToken.None; + var generalIdRef = new GeneralIdRef(); + + _specificationManagerMock.Setup(x => x.GetTemplateForPrintSpec(generalIdRef, cancellationToken)).ReturnsAsync(templateGeneralIdRef); + + //Act + var actualResult = await _specificationController.GetTemplateForPrintSpec(generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(GeneralIdRef))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/SpecificationControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/SpecificationControllerTestBase.cs new file mode 100644 index 0000000..a7541e2 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SpecificationControllerUnitTests/SpecificationControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.SpecificationControllerUnitTests; + +public abstract class SpecificationControllerTestBase : TestBase +{ + protected Mock _specificationManagerMock = null!; + protected SpecificationController _specificationController = null!; + + public override async Task Setup() + { + await base.Setup(); + _specificationManagerMock = new Mock(); + _specificationController = new SpecificationController(_specificationManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _specificationController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/AddProviderUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/AddProviderUnitTests.cs new file mode 100644 index 0000000..256ee83 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/AddProviderUnitTests.cs @@ -0,0 +1,33 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SsoManagerControllerUnitTests; + +[TestFixture] +public class AddProviderUnitTests : SsoProivderControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task AddProvider_WhenCalled_ReturnsOk() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var ssoProvider = new CreateSsoProvider(); + + //Act + var actualResult = await SsoManagerController.AddProvider(ssoProvider, cancellationToken); + + //Assert + SsoManagerMock.Verify(x => x.AddSsoProviderAsync(It.IsAny(), ssoProvider, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/DeleteSsoProviderUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/DeleteSsoProviderUnitTests.cs new file mode 100644 index 0000000..56b1aba --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/DeleteSsoProviderUnitTests.cs @@ -0,0 +1,33 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SsoManagerControllerUnitTests; + +[TestFixture] +public class DeleteSsoProviderUnitTests : SsoProivderControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditSsoProvider_WhenCalled_ReturnsOk() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var generalIdRef = new GeneralIdRef(); + + //Act + var actualResult = await SsoManagerController.DeleteSsoProvider(generalIdRef, cancellationToken); + + //Assert + SsoManagerMock.Verify(x => x.RemoveSsoProviderAsync(It.IsAny(), generalIdRef, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/EditSsoProviderUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/EditSsoProviderUnitTests.cs new file mode 100644 index 0000000..015aa67 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/EditSsoProviderUnitTests.cs @@ -0,0 +1,33 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SsoManagerControllerUnitTests; + +[TestFixture] +public class EditSsoProviderUnitTests : SsoProivderControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditSsoProvider_WhenCalled_ReturnsOk() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var ssoProvider = new EditSsoProvider(); + + //Act + var actualResult = await SsoManagerController.EditSsoProvider(ssoProvider, cancellationToken); + + //Assert + SsoManagerMock.Verify(x => x.EditSsoProviderAsync(It.IsAny(), ssoProvider, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/GetProviderUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/GetProviderUnitTests.cs new file mode 100644 index 0000000..792268d --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/GetProviderUnitTests.cs @@ -0,0 +1,56 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SsoManagerControllerUnitTests; + +[TestFixture] +public class GetProviderUnitTests : SsoProivderControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSsoProviderAsync_ByGuidOnly_ReturnsOk() + { + //Arrange + var guid = new Guid("db016cab-ca37-4c44-bcb1-78bf4c6ec800"); + var providerName = "TestName"; + long id = 1; + var idRef = new GeneralIdRef + { + Guid = guid, + Id = null + }; + + var formObj = new ReadSsoProvider() + { + Name = providerName, + Id = id, + Guid = guid, + }; + SsoManagerMock! + .Setup(x => x.GetSsoProviderAsync(It.Is(f => f.Id == null && f.Guid == guid), + It.IsAny())).ReturnsAsync(formObj); + + //Act + var res = await SsoManagerController.GetProvider(idRef); + + //Assert + var objectResult = res as OkObjectResult; + Assert.That(objectResult?.Value, Is.Not.Null); + if (objectResult?.Value is not null) + { + Assert.That(objectResult.Value.GetType(), Is.EqualTo(typeof(ReadSsoProvider))); + var form = objectResult?.Value as ReadSsoProvider; + Assert.That(form?.Name, Is.EqualTo(providerName)); + Assert.That(form?.Guid, Is.EqualTo(guid)); + Assert.That(form?.Id, Is.EqualTo(id)); + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/GetProvidersUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/GetProvidersUnitTests.cs new file mode 100644 index 0000000..8146a80 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/GetProvidersUnitTests.cs @@ -0,0 +1,42 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.SsoManagerControllerUnitTests; + +[TestFixture] +public class GetProvidersUnitTests : SsoProivderControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSsoProvidersAsync_NormalConditions_ReturnsOkObjResult() + { + //Arrange + var paginatedData = new PaginatedData + { + Count = 2, + Data = new List { new() }, + Page = 1, + PageSize = 10 + }; + + SsoManagerMock?.Setup(x => x.GetSsoProvidersAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(paginatedData); + + var paging = new Paging(); + + //Act + var res = await SsoManagerController.GetProviders(paging); + + //Assert + Assert.That(res, Is.Not.Null); + Assert.That(res?.GetType(), Is.EqualTo(typeof(OkObjectResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/SiteControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/SiteControllerTestBase.cs new file mode 100644 index 0000000..ddf4fe1 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/SsoManagerControllerUnitTests/SiteControllerTestBase.cs @@ -0,0 +1,44 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.SsoManagerControllerUnitTests; + +public abstract class SsoProivderControllerTestBase : TestBase +{ + protected Mock SsoManagerMock = null!; + protected SsoManagerController SsoManagerController = null!; + + public override async Task Setup() + { + await base.Setup(); + SsoManagerMock = new Mock(); + SsoManagerController = new SsoManagerController(SsoManagerMock.Object); + + const long id = -1; + const string email = "email@mail.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + SsoManagerController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/CreateUserUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/CreateUserUnitTests.cs new file mode 100644 index 0000000..0a5e08b --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/CreateUserUnitTests.cs @@ -0,0 +1,76 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class CreateUserUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CreateUser_UserAlreadyExists_Error() + { + //Arrange + var userRegistration = new UserRegistration + { + Email = "test@testy.test" + }; + + _userManagerMock.Setup(x => x.CreateUser(It.IsAny(), userRegistration, It.IsAny())).Throws(new ExistsException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _userManagerController.CreateUser(userRegistration); + }); + } + + [Test] + public async Task CreateUser_UserDoesNotExist_ReturnsOK() + { + //Arrange + var userRegistration = new UserRegistration + { + Email = "test@testy.test" + }; + + //Act + var actualResult = await _userManagerController.CreateUser(userRegistration); + + //Assert + _userManagerMock.Verify(x => x.CreateUser(It.IsAny(), userRegistration, It.IsAny()), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } + + [Test] + public void CreateUser_BadRequest_ReturnError() + { + //Arrange + var userRegistration = new UserRegistration + { + Email = "test@testy.test" + }; + + var message = "This is a test message"; + + _userManagerMock.Setup(x => x.CreateUser(It.IsAny(), userRegistration, It.IsAny())).Throws(new ArgumentException(message)); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _userManagerController.CreateUser(userRegistration); + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/CurrentEmailUserActionUrlUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/CurrentEmailUserActionUrlUnitTests.cs new file mode 100644 index 0000000..b9bd5ef --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/CurrentEmailUserActionUrlUnitTests.cs @@ -0,0 +1,57 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Models; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class CurrentEmailUserActionUrlUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CurrentEmailUserActionUrl_UserIsNull_ThrowsArgumentNullException() + { + //Arrange + string email = null!; + var emailUserActionType = EmailUserActionType.ConfirmEmailAddress; + + _userManagerMock + .Setup(x => x.GetCurrentEmailActionUrl(It.IsAny(), It.IsAny(), + It.IsAny())).Throws(); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _userManagerController.CurrentEmailUserActionUrl(email, emailUserActionType, CancellationToken.None); + }); + } + + [Test] + public async Task CurrentEmailUserActionUrl_Found_ReturnsUrl() + { + //Arrange + const string email = "test@test.test"; + const EmailUserActionType emailUserActionType = EmailUserActionType.ConfirmEmailAddress; + + const string okResult = "OKResult"; + + _userManagerMock + .Setup(x => x.GetCurrentEmailActionUrl(email, emailUserActionType, + It.IsAny())).ReturnsAsync(okResult); + + //Act + var actualResult = await _userManagerController.CurrentEmailUserActionUrl(email, emailUserActionType, CancellationToken.None); + + //Assert + Assert.That(actualResult, Is.TypeOf(typeof(OkObjectResult))); + Assert.That(((OkObjectResult)actualResult).Value, Is.EqualTo(okResult)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/DeactivateUserUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/DeactivateUserUnitTests.cs new file mode 100644 index 0000000..9e3a828 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/DeactivateUserUnitTests.cs @@ -0,0 +1,91 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using eSuite.API.Models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class DeactivateUserUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeactivateUser_ActiveUser_ReturnsOK() + { + //Arrange + var email = new EmailAddress + { + Email = "deactivate.me@sun-strategy.com" + }; + + //Act + var actualResult = await _userManagerController.DeactivateUser(email); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + + _userManagerMock.Verify(x => x.DeactivateUser(It.IsAny(), email.Email, It.IsAny()), Times.Once); + } + + [Test] + public void DeactivateUser_UserNotFound_Returns404() + { + //Arrange + var email = new EmailAddress + { + Email = "deactivate.me@sun-strategy.com" + }; + + _userManagerMock.Setup(x => x.DeactivateUser(It.IsAny(), email.Email, It.IsAny())).Throws(() => new NotFoundException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _userManagerController.DeactivateUser(email); + }); + } + + [Test] + public void DeactivateUser_UserAlreadyDeactivated_ReturnsBadRequest() + { + //Arrange + var email = new EmailAddress + { + Email = "deactivate.me@sun-strategy.com" + }; + + _userManagerMock.Setup(x => x.DeactivateUser(It.IsAny(), email.Email, It.IsAny())).Throws(() => new InvalidOperationException()); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _userManagerController.DeactivateUser(email); + }); + } + + [Test] + public async Task DeactivateUserByGeneralIdRef_UserAlreadyDeactivated_ReturnsBadRequest() + { + //Arrange + var cancellationToken = CancellationToken.None; + + var user = new GeneralIdRef(); + + //Act + var actualResult = await _userManagerController.DeactivateUser(user, cancellationToken); + + //Assert + _userManagerMock.Verify(x => x.DeactivateUser(It.IsAny(), user, cancellationToken), Times.Once); + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/EditUserUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/EditUserUnitTests.cs new file mode 100644 index 0000000..aa5f2fb --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/EditUserUnitTests.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class EditUserUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetUsers_WhenCalled_ReturnsPagedData() + { + //Arrange + var user = new EditUser(); + var cancellationToken = CancellationToken.None; + + //Act + var actualResult = await _userManagerController.EditUser(user, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + _userManagerMock.Verify(x => x.EditUser(It.IsAny(), user, cancellationToken), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/GetUserUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/GetUserUnitTests.cs new file mode 100644 index 0000000..09a80f5 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/GetUserUnitTests.cs @@ -0,0 +1,39 @@ +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class GetUserUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetUsers_WhenCalled_ReturnsPagedData() + { + //Arrange + var user = new GetUser(); + + var cancellationToken = CancellationToken.None; + var generalIdRef = new GeneralIdRef(); + + _userManagerMock.Setup(x => x.GetUserAsync(generalIdRef, cancellationToken)).ReturnsAsync(user); + + //Act + var actualResult = await _userManagerController.GetUser(generalIdRef, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.EqualTo(user)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/GetUsersUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/GetUsersUnitTests.cs new file mode 100644 index 0000000..92002d8 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/GetUsersUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class GetUsersUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetUsers_WhenCalled_ReturnsPagedData() + { + //Arrange + var domains = new List(); + + var paginatedData = new PaginatedData + { + Count = domains.Count, + Data = domains, + Page = 1, + PageSize = 10 + }; + + var cancellationToken = CancellationToken.None; + + var paging = new Paging(); + + _userManagerMock.Setup(x => x.GetUsersAsync(paging, cancellationToken)).ReturnsAsync(paginatedData); + + //Act + var actualResult = await _userManagerController.GetUsers(paging, cancellationToken); + + //Assert + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkObjectResult))); + var objectResult = actualResult as OkObjectResult; + + Assert.That(objectResult?.StatusCode, Is.EqualTo(200)); + Assert.That(objectResult?.Value, Is.Not.Null); + Assert.That(objectResult!.Value!.GetType, Is.EqualTo(typeof(PaginatedData))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/ResendConfirmEmailUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/ResendConfirmEmailUnitTests.cs new file mode 100644 index 0000000..9749ef4 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/ResendConfirmEmailUnitTests.cs @@ -0,0 +1,49 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +[TestFixture] +public class ResendConfirmEmailUnitTests : UserManagerControllerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ResendConfirmEmail_UserIsNull_ThrowsArgumentNullException() + { + //Arrange + GeneralIdRef userId = null!; + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await _userManagerController.ResendConfirmEmail(userId, CancellationToken.None); + }); + } + + [Test] + public async Task ResendConfirmEmail_UserSupplied_CallerUserManager() + { + //Arrange + var userId = new GeneralIdRef + { + Guid = new Guid("5cb7c467-5454-416d-91db-1cb795c0d3e4") + }; + + //Act + var actualResult = await _userManagerController.ResendConfirmEmail(userId, CancellationToken.None); + + //Assert + _userManagerMock.Verify(x => x.ResendConfirmEmail(It.IsAny(), userId, It.IsAny()), Times.Once); + + Assert.That(actualResult.GetType(), Is.EqualTo(typeof(OkResult))); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/UserManagerControllerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/UserManagerControllerTestBase.cs new file mode 100644 index 0000000..318e158 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Controllers/UserManagerControllerUnitTests/UserManagerControllerTestBase.cs @@ -0,0 +1,53 @@ +using System.Security.Claims; +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.Controllers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; + +namespace eSuite.API.UnitTests.Controllers.UserManagerControllerUnitTests; + +public abstract class UserManagerControllerTestBase : TestBase +{ + protected UserController _userManagerController = null!; + protected Mock _userManagerMock = null!; + protected Mock _roleManagerMock = null!; + + protected const string AccessDeniedText = "Access denied"; + protected const string BadRequestText = "Bad request"; + protected const string NotFoundText = "Not found"; + protected const string LoginAcceptedText = "Login accepted"; + + public override async Task Setup() + { + await base.Setup(); + + _userManagerMock = new Mock(); + _roleManagerMock = new Mock(); + + _userManagerController = new UserController(_userManagerMock.Object, _roleManagerMock.Object); + + const long id = -1; + const string email = "test@test.test"; + const string displayName = "Testy McTester"; + + AddAuthorisedUserToController(id, email, displayName); + } + + protected void AddAuthorisedUserToController(long id, string email, string displayName) + { + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.PrimarySid, id.ToString()), + new(ClaimTypes.Email, email), + new(ClaimTypes.Name, displayName) + // other required and custom claims + }, "TestAuthentication")); + + _userManagerController.ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext { User = user } + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/HealthChecks/SmtpHealthCheckUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/HealthChecks/SmtpHealthCheckUnitTests.cs new file mode 100644 index 0000000..140cc8f --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/HealthChecks/SmtpHealthCheckUnitTests.cs @@ -0,0 +1,168 @@ +using System.Net; +using System.Net.Sockets; +using e_suite.UnitTestCore; +using eSuite.API.HealthChecks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.HealthChecks; + +[TestFixture] +public class SmtpHealthCheckUnitTests : TestBase +{ + private Mock _socketFactoryMock = null!; + private Mock _socketFacadeMock = null!; + + [SetUp] + public override async Task Setup() + { + await base.Setup(); + + _socketFacadeMock = new Mock(); + _socketFacadeMock.Setup(x => x.Connect(It.IsAny())).Callback(() => {}); + + _socketFactoryMock = new Mock(); + _socketFactoryMock + .Setup(x => x.CreateSocket(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(_socketFacadeMock.Object); + } + + [Test] + public void SmtpHealthCheck_Healthy_WhenEverythingWorking_ReturnsHealthy() + { + //Arrange + var socketAvailable = 50; + _socketFacadeMock.SetupGet(x => x.Available).Returns(() => socketAvailable); + + var sendCounter = 0; + + _socketFacadeMock + .Setup(x => x.Send(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback( + (data, offset, size, flags) => + { + sendCounter++; + }); + + _socketFacadeMock + .Setup(x => x.Receive(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback( + (data, offset, size, flags) => + { + if (sendCounter == 0) + { + data[0] = 50; //2 + data[1] = 50; //2 + data[2] = 48; //0 + data[3] = 0; //terminator + } + if (sendCounter == 1) + { + data[0] = 50; //2 + data[1] = 53; //5 + data[2] = 48; //0 + data[3] = 0; //terminator + } + }); + + //Act + var result = SmtpHealthCheck.Healthy(_configuration, _socketFactoryMock.Object); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Status, Is.EqualTo(HealthStatus.Healthy)); + } + + [Test] + public void SmtpHealthCheck_Healthy_WhenServerRepondsIncorrectlyOnInitialConnection_ReturnsUnHealthy() + { + //Arrange + var socketAvailable = 50; + _socketFacadeMock.SetupGet(x => x.Available).Returns(() => socketAvailable); + + var sendCounter = 0; + + _socketFacadeMock + .Setup(x => x.Send(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback( + (data, offset, size, flags) => + { + sendCounter++; + }); + + _socketFacadeMock + .Setup(x => x.Receive(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback( + (data, offset, size, flags) => + { + if (sendCounter == 0) + { + data[0] = 50; //2 + data[1] = 53; //5 -- should be a 2, for healthy + data[2] = 48; //0 + data[3] = 0; //terminator + } + if (sendCounter == 1) + { + data[0] = 50; //2 + data[1] = 53; //5 + data[2] = 48; //0 + data[3] = 0; //terminator + } + }); + + //Act + var result = SmtpHealthCheck.Healthy(_configuration, _socketFactoryMock.Object); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Status, Is.EqualTo(HealthStatus.Unhealthy)); + } + + [Test] + public void SmtpHealthCheck_Healthy_WhenServerRepondsToHeloCheck_ReturnsUnHealthy() + { + //Arrange + var socketAvailable = 50; + _socketFacadeMock.SetupGet(x => x.Available).Returns(() => socketAvailable); + + var sendCounter = 0; + + _socketFacadeMock + .Setup(x => x.Send(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback( + (data, offset, size, flags) => + { + sendCounter++; + }); + + _socketFacadeMock + .Setup(x => x.Receive(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback( + (data, offset, size, flags) => + { + if (sendCounter == 0) + { + data[0] = 50; //2 + data[1] = 50; //2 + data[2] = 48; //0 + data[3] = 0; //terminator + } + if (sendCounter == 1) + { + data[0] = 50; //2 + data[1] = 48; //0 -- Should be a 5 for healthy + data[2] = 48; //0 + data[3] = 0; //terminator + } + }); + + //Act + var result = SmtpHealthCheck.Healthy(_configuration, _socketFactoryMock.Object); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Status, Is.EqualTo(HealthStatus.Unhealthy)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Middleware/ExceptionCaptureUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Middleware/ExceptionCaptureUnitTests.cs new file mode 100644 index 0000000..8963f9c --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Middleware/ExceptionCaptureUnitTests.cs @@ -0,0 +1,317 @@ +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Extensions.Exceptions; +using eSuite.API.Middleware; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Newtonsoft.Json; +using NUnit.Framework; +using System.ComponentModel.DataAnnotations; + +namespace eSuite.API.UnitTests.Middleware; + +[TestFixture] +public class ExceptionCaptureUnitTests +{ + private Mock _requestDelegateMock = null!; + private readonly Mock _exceptionLoggerMock = new Mock()!; + private ExceptionCapture _exceptionCaptureMiddleWare = null!; + + [SetUp] + public void Setup() + { + _requestDelegateMock = new Mock(); + _exceptionCaptureMiddleWare = new ExceptionCapture(_requestDelegateMock.Object, _exceptionLoggerMock.Object); + } + + [Test] + public void ExceptionMiddleWare_WhenCalled_InvokeCalledAndNoExceptionThrown() + { + //Arrange + var context = new DefaultHttpContext(); + + //Assert + Assert.DoesNotThrowAsync(async () => + { + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + }); + _requestDelegateMock.Verify(x => x.Invoke(context), Times.Once); + } + + [Test] + public async Task ExceptionMiddleWare_WhenGuidMismatchThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws( () => new GuidMismatchException("Test error")); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Test error")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenNotFoundExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status404NotFound)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Not found")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'e_suite.API.Common.exceptions.NotFoundException' was thrown.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenExistsExceptionExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'e_suite.API.Common.exceptions.ExistsException' was thrown.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenInvalidOperationExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Operation is not valid due to the current state of the object.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenValidationExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'System.ComponentModel.DataAnnotations.ValidationException' was thrown.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenArgumentExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Value does not fall within the expected range.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenInvalidReferenceObjectIdThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'e_suite.API.Common.exceptions.InvalidReferenceObjectId' was thrown.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenTokenInvalidExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'e_suite.API.Common.exceptions.TokenInvalidException' was thrown.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenInvalidEmailExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Bad request")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'e_suite.API.Common.exceptions.InvalidEmailException' was thrown.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenOperationCanceledExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status400BadRequest)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Request cancelled")); + Assert.That(problem!.Detail, Is.EqualTo("The operation was canceled.")); + } + + [Test] + public async Task ExceptionMiddleWare_WhenUnhandledExceptionThrow_ExpectedResponseReturned() + { + //Arrange + var context = new DefaultHttpContext(); + context.Response.Body = new MemoryStream(); + + _requestDelegateMock.Setup(x => x.Invoke(context)).Throws(); + + //Act + await _exceptionCaptureMiddleWare.InvokeAsync(context); + + //Assert + Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status500InternalServerError)); + + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Response.Body); + var streamText = reader.ReadToEnd(); + var problem = JsonConvert.DeserializeObject(streamText); + + Assert.That(problem, Is.Not.Null); + Assert.That(problem!.Title, Is.EqualTo("Internal Server Error")); + Assert.That(problem!.Detail, Is.EqualTo("Exception of type 'System.Exception' was thrown.")); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/Middleware/OptionsMiddlewareUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/Middleware/OptionsMiddlewareUnitTests.cs new file mode 100644 index 0000000..eae2cbc --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/Middleware/OptionsMiddlewareUnitTests.cs @@ -0,0 +1,60 @@ +using eSuite.API.Middleware; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.Middleware; + +[TestFixture] +public class OptionsMiddlewareUnitTests +{ + private Mock _requestDelegateMock = null!; + private OptionsMiddleware _optionsMiddleWare = null!; + + [SetUp] + public void Setup() + { + _requestDelegateMock = new Mock(); + _optionsMiddleWare = new OptionsMiddleware(_requestDelegateMock.Object); + } + + [Test] + public async Task OptionsMiddleware_WhenCalledWithNonOptionsMethod_CallsNextMiddleWare() + { + //Arrange + var context = new DefaultHttpContext(); + + + //Act + await _optionsMiddleWare.Invoke(context); + + //Assert + _requestDelegateMock.Verify(x => x.Invoke(context), Times.Once); + } + + [Test] + public async Task OptionsMiddleware_WhenCalledWithOptionsMethod_CallsNextMiddleWare() + { + //Arrange + var origin = "TestOrigin"; + + var context = new DefaultHttpContext(); + context.Request.Method = "OPTIONS"; + context.Request.Headers.Origin = origin; + + + //Act + await _optionsMiddleWare.Invoke(context); + + //Assert + _requestDelegateMock.Verify(x => x.Invoke(context), Times.Never); + + Assert.That(context.Response.StatusCode, Is.EqualTo(200)); + Assert.That(context.Response.Headers.AccessControlAllowOrigin.ToString(), Is.EqualTo(origin)); + Assert.That(context.Response.Headers.AccessControlAllowHeaders, + Is.EqualTo(new[] { "Origin, X-Requested-With, Content-Type, Accept, Authorization" })); + Assert.That(context.Response.Headers.AccessControlAllowMethods, Is.EqualTo(new[] { "GET, POST, PUT, DELETE, OPTIONS" })); + Assert.That(context.Response.Headers.AccessControlAllowCredentials, Is.EqualTo(new[] { "true" })); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CookieManagerTestBase.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CookieManagerTestBase.cs new file mode 100644 index 0000000..968d762 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CookieManagerTestBase.cs @@ -0,0 +1,19 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using Moq; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +public class CookieManagerTestBase : TestBase +{ + protected API.SingleSignOn.CookieManager _cookieManager = null!; + protected Mock _userManagerMock = null!; + + public override async Task Setup() + { + await base.Setup(); + _userManagerMock = new Mock(); + + _cookieManager = new API.SingleSignOn.CookieManager(_userManagerMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateProfileLinkCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateProfileLinkCookieUnitTests.cs new file mode 100644 index 0000000..b18cf79 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateProfileLinkCookieUnitTests.cs @@ -0,0 +1,58 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class CreateProfileLinkCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSessionCookie_WhenCalled_AddsSessionCookieToResponseWithCorrectSettings() + { + //Arrange + var cookies = new FakeResponseCookies(); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 69, + Comment = string.Empty + }; + + var generalIdRef = new GeneralIdRef + { + Id = 69 + }; + + var singleUseGuid = new Guid("{52A3CF29-E622-41B4-9431-46B3F6B6D16A}"); + + _userManagerMock.Setup(x => x.CreateSingleUseGuid(auditUserDetails, generalIdRef, It.IsAny())) + .ReturnsAsync(singleUseGuid); + + //Act + await _cookieManager.CreateProfileLinkCookie(httpResponseMock.Object, auditUserDetails, generalIdRef, CancellationToken.None ); + + //Assert + Assert.That(cookies.CookieDictionary["eSuiteProfileLinkCookie"], Is.Not.Null); + Assert.That(cookies.CookieDictionary["eSuiteProfileLinkCookie"].Value, Is.EqualTo(singleUseGuid.ToString())); + var cookieOptions = cookies.CookieDictionary["eSuiteProfileLinkCookie"].CookieOptions!; + Assert.That(cookieOptions.Expires, Is.Null); + Assert.That(cookieOptions.HttpOnly, Is.True); //Is only ever ready by the ASP Code, Javascript is banned. + Assert.That(cookieOptions.IsEssential, Is.True); + Assert.That(cookieOptions.Secure, Is.True); + Assert.That(cookieOptions.SameSite, Is.EqualTo(SameSiteMode.Lax)); //This cookie is used when the Sso Provider is calling back after authorisation + Assert.That(cookieOptions.Path, Is.EqualTo("/")); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateSessionCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateSessionCookieUnitTests.cs new file mode 100644 index 0000000..517f0af --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateSessionCookieUnitTests.cs @@ -0,0 +1,46 @@ +using e_suite.API.Common.models; +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class CreateSessionCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSessionCookie_WhenCalled_AddsSessionCookieToResponseWithCorrectSettings() + { + //Arrange + var cookies = new FakeResponseCookies(); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + var loginResponse = new LoginResponse + { + Result = LoginResult.Success, + Token = "JSON Web Token" + }; + + //Act + await _cookieManager.CreateSessionCookie(httpResponseMock.Object, loginResponse); + + //Assert + Assert.That(cookies.CookieDictionary["eSuiteSession"], Is.Not.Null); + Assert.That(cookies.CookieDictionary["eSuiteSession"].Value, Is.EqualTo(loginResponse.Token)); + var cookieOptions = cookies.CookieDictionary["eSuiteSession"].CookieOptions!; + Assert.That(cookieOptions.Expires, Is.Null); + Assert.That(cookieOptions.HttpOnly, Is.False); //Needs to be false to be readable by Javascript (React) + Assert.That(cookieOptions.IsEssential, Is.True); + Assert.That(cookieOptions.Secure, Is.True); + Assert.That(cookieOptions.SameSite, Is.EqualTo(SameSiteMode.Strict)); //Don't allow cross site calls to include the cookie + Assert.That(cookieOptions.Path, Is.EqualTo("/")); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateSsoIdCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateSsoIdCookieUnitTests.cs new file mode 100644 index 0000000..d1674a1 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/CreateSsoIdCookieUnitTests.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class CreateSsoIdCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSsoIdCookie_WhenCalled_AddsCookieToResponseWithCorrectSettings() + { + //Arrange + var cookies = new FakeResponseCookies(); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + var ssoId = 12345; + + //Act + await _cookieManager.CreateSsoIdCookie(httpResponseMock.Object, ssoId); + + //Assert + Assert.That(cookies.CookieDictionary["eSuiteSsoProvider"], Is.Not.Null); + Assert.That(cookies.CookieDictionary["eSuiteSsoProvider"].Value, Is.EqualTo(ssoId.ToString())); + var cookieOptions = cookies.CookieDictionary["eSuiteSsoProvider"].CookieOptions!; + Assert.That(cookieOptions.Expires, Is.Not.Null); //Not a session cookie, so can last for a while between sessions. + Assert.That(cookieOptions.HttpOnly, Is.True); //Does not need to be read by anything else. + Assert.That(cookieOptions.IsEssential, Is.True); + Assert.That(cookieOptions.Secure, Is.True); + Assert.That(cookieOptions.SameSite, Is.EqualTo(SameSiteMode.Strict)); //Don't allow cross site calls to include the cookie + Assert.That(cookieOptions.Path, Is.EqualTo("/")); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteLinkCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteLinkCookieUnitTests.cs new file mode 100644 index 0000000..a8dcbb6 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteLinkCookieUnitTests.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class DeleteLinkCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteLinkCookie_WhenCalledAndCookiePresent_RemovesCookieFromResponse() + { + //Arrange + var cookies = new FakeResponseCookies(); + + cookies.Append("eSuiteProfileLinkCookie", "Guid", new CookieOptions + { + }); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + //Act + await _cookieManager.DeleteLinkCookie(httpResponseMock.Object); + + //Assert + Assert.That(cookies.CookieDictionary.ContainsKey("eSuiteProfileLinkCookie"), Is.False); + } + + [Test] + public async Task DeleteLinkCookie_WhenCalledAndCookieNotPresent_DoesNothingGraceFully() + { + //Arrange + var cookies = new FakeResponseCookies(); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + //Act + await _cookieManager.DeleteLinkCookie(httpResponseMock.Object); + + //Assert + Assert.That(cookies.CookieDictionary.ContainsKey("eSuiteProfileLinkCookie"), Is.False); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteSessionCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteSessionCookieUnitTests.cs new file mode 100644 index 0000000..8d62a8b --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteSessionCookieUnitTests.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class DeleteSessionCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteSessionCookie_WhenCalledAndCookiePresent_RemovesSessionCookieFromResponse() + { + //Arrange + var cookies = new FakeResponseCookies(); + + cookies.Append("eSuiteSession", "JSON Web Token", new CookieOptions + { + HttpOnly = false, //Set False as Javascript (React) needs to read the cookie. + SameSite = SameSiteMode.Strict, + Secure = true, + IsEssential = true, + Expires = null, //Session Cookie + Path = "/" + }); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + //Act + await _cookieManager.DeleteSessionCookie(httpResponseMock.Object); + + //Assert + Assert.That(cookies.CookieDictionary.ContainsKey("eSuiteSession"), Is.False); + } + + [Test] + public async Task DeleteSessionCookie_WhenCalledAndCookieNotPresent_DoesNothingGraceFully() + { + //Arrange + var cookies = new FakeResponseCookies(); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + //Act + await _cookieManager.DeleteSessionCookie(httpResponseMock.Object); + + //Assert + Assert.That(cookies.CookieDictionary.ContainsKey("eSuiteSession"), Is.False); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteSsoIdCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteSsoIdCookieUnitTests.cs new file mode 100644 index 0000000..4346a56 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/DeleteSsoIdCookieUnitTests.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class DeleteSsoIdCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeleteSsoIdCookie_WhenCalledAndCookiePresent_RemovesCookieFromResponse() + { + //Arrange + var cookies = new FakeResponseCookies(); + + cookies.Append("eSuiteSsoProvider", "12345", new CookieOptions + { + }); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + //Act + await _cookieManager.DeleteSsoIdCookie(httpResponseMock.Object); + + //Assert + Assert.That(cookies.CookieDictionary.ContainsKey("eSuiteSsoProvider"), Is.False); + } + + [Test] + public async Task DeleteSsoIdCookie_WhenCalledAndCookieNotPresent_DoesNothingGraceFully() + { + //Arrange + var cookies = new FakeResponseCookies(); + + var httpResponseMock = new Mock(); + httpResponseMock.SetupGet(x => x.Cookies).Returns(cookies); + + //Act + await _cookieManager.DeleteSsoIdCookie(httpResponseMock.Object); + + //Assert + Assert.That(cookies.CookieDictionary.ContainsKey("eSuiteSsoProvider"), Is.False); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeCookie.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeCookie.cs new file mode 100644 index 0000000..b5d8038 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeCookie.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Http; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +public class FakeCookie +{ + public string Value { get; set; } = string.Empty; + public CookieOptions? CookieOptions { get; set; } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeRequestCookieCollection.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeRequestCookieCollection.cs new file mode 100644 index 0000000..7bd6188 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeRequestCookieCollection.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Http; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +public class FakeRequestCookieCollection : Dictionary, IRequestCookieCollection +{ + public new ICollection Keys => base.Keys; + public new string? this[string key] + { + get => base[key]; + set => base[key] = value!; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeResponseCookies.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeResponseCookies.cs new file mode 100644 index 0000000..2d7d999 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/FakeResponseCookies.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Http; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +public class FakeResponseCookies : IResponseCookies +{ + public Dictionary CookieDictionary { get; set; } = new(); + + public void Append(string key, string value) + { + throw new NotImplementedException(); + } + + public void Append(string key, string value, CookieOptions options) + { + CookieDictionary.Add(key, new FakeCookie + { + Value = value, + CookieOptions = options + }); + } + + public void Delete(string key) + { + if (CookieDictionary.ContainsKey(key)) + CookieDictionary.Remove(key); + } + + public void Delete(string key, CookieOptions options) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/GetSsoIdFromSsoIdCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/GetSsoIdFromSsoIdCookieUnitTests.cs new file mode 100644 index 0000000..04bdd29 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/GetSsoIdFromSsoIdCookieUnitTests.cs @@ -0,0 +1,90 @@ +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class GetSsoIdFromSsoIdCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSsoIdFromSsoId_WhenCookieNotPresent_ReturnsNull() + { + //Arrange + var fakeRequestCookieCollection = new FakeRequestCookieCollection(); + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act + var result = await _cookieManager.GetSsoIdFromSsoIdCookie(httpRequestMock.Object); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public async Task GetSsoIdFromSsoId_WhenCookieValueIsNull_ReturnsNull() + { + //Arrange + var fakeRequestCookieCollection = new FakeRequestCookieCollection + { + { "eSuiteSsoProvider", null! } + }; + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act + var result = await _cookieManager.GetSsoIdFromSsoIdCookie(httpRequestMock.Object); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public async Task GetSsoIdFromSsoId_WhenCookieValueIsNotANumber_ReturnsNull() + { + //Arrange + var fakeRequestCookieCollection = new FakeRequestCookieCollection + { + { "eSuiteSsoProvider", "Not a number" } + }; + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act + var result = await _cookieManager.GetSsoIdFromSsoIdCookie(httpRequestMock.Object); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public async Task GetSsoIdFromSsoId_WhenCookieValueIsANumber_ReturnsLong() + { + //Arrange + var expectedResult = 12345; + + var fakeRequestCookieCollection = new FakeRequestCookieCollection + { + { "eSuiteSsoProvider", expectedResult.ToString() } + }; + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act + var result = await _cookieManager.GetSsoIdFromSsoIdCookie(httpRequestMock.Object); + + //Assert + Assert.That(result, Is.EqualTo(expectedResult)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/GetUserIdFromProfileLinkCookieUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/GetUserIdFromProfileLinkCookieUnitTests.cs new file mode 100644 index 0000000..94cd184 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/CookieManager/GetUserIdFromProfileLinkCookieUnitTests.cs @@ -0,0 +1,107 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.API.SingleSignOn; +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.CookieManager; + +[TestFixture] +public class GetUserIdFromLinkCookieUnitTests : CookieManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetUserIdFromLinkCookie_WhenCookieNotPresent_ReturnsNull() + { + //Arrange + var fakeRequestCookieCollection = new FakeRequestCookieCollection(); + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act + var result = await _cookieManager.GetUserIdFromLinkCookie(httpRequestMock.Object, CancellationToken.None); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public void GetUserIdFromLinkCookie_WhenCookieValueIsNull_ThrowsNotFoundException() + { + //Arrange + var fakeRequestCookieCollection = new FakeRequestCookieCollection + { + { "eSuiteProfileLinkCookie", null! } + }; + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + var result = + await _cookieManager.GetUserIdFromLinkCookie(httpRequestMock.Object, CancellationToken.None); + }); + } + + [Test] + public async Task GetUserIdFromLinkCookie_WhenCookieValueIsInvalidCookie_ReturnsNullUser() + { + //Arrange + var guid = new Guid("{AF29B4B6-3FBF-4C96-8577-2F12B9E56FBE}"); + + var fakeRequestCookieCollection = new FakeRequestCookieCollection + { + { "eSuiteProfileLinkCookie", guid.ToString() } + }; + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + //Act + var result = await _cookieManager.GetUserIdFromLinkCookie(httpRequestMock.Object, CancellationToken.None); + + //Assert + Assert.That(result?.User, Is.Null); + Assert.That(result?.LinkType, Is.EqualTo(LinkType.Profile)); + _userManagerMock.Verify( x=> x.GetUserWithSingleUseGuid(guid, It.IsAny()),Times.Once); + } + + [Test] + public async Task GetUserIdFromLinkCookie_WhenCookieValueIsValidCookie_ReturnsUser() + { + //Arrange + var guid = new Guid("{AF29B4B6-3FBF-4C96-8577-2F12B9E56FBE}"); + + var fakeRequestCookieCollection = new FakeRequestCookieCollection + { + { "eSuiteProfileLinkCookie", guid.ToString() } + }; + + var httpRequestMock = new Mock(); + httpRequestMock.Setup(x => x.Cookies).Returns(fakeRequestCookieCollection); + + var user = new User + { + Id = 72, + FirstName = "Testy", + LastName = "McTester" + }; + + _userManagerMock.Setup(x => x.GetUserWithSingleUseGuid(guid, It.IsAny())).ReturnsAsync(user); + + //Act + var result = await _cookieManager.GetUserIdFromLinkCookie(httpRequestMock.Object, CancellationToken.None); + + //Assert + Assert.That(result?.User, Is.EqualTo(user)); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/ExchangeAuthorisationTokenUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/ExchangeAuthorisationTokenUnitTests.cs new file mode 100644 index 0000000..9e4373e --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/ExchangeAuthorisationTokenUnitTests.cs @@ -0,0 +1,208 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.API.Middleware; +using eSuite.API.SingleSignOn; +using Microsoft.IdentityModel.Tokens; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.SingleSignOn; + +[TestFixture] +public class ExchangeAuthorisationTokenUnitTests : SingleSignOnTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ExchangeAuthorisationToken_WhenSsoProviderNotFound_ThrowsNotFoundException() + { + //Arrange + var ssoProviderId = 123; + var code = "21kj345ghl2jk13b4"; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await _singleSignOn.ExchangeAuthorisationToken(ssoProviderId, code, CancellationToken.None); + }); + } + + [Test] + public void ExchangeAuthorisationToken_WhenSsoProviderReturnsInvalidOpenIdResponse_ThrowsNullReferenceException() + { + //Arrange + var ssoProviderId = 123; + var code = "21kj345ghl2jk13b4"; + + var ssoProvider = new SsoProvider + { + Id = ssoProviderId, + AuthorizationEndpoint = "https://validIssuer.com/authorisationEndPoint", + ClientId = "clientId", + ClientSecret = "clientSecret", + Deleted = false, + IsPublic = true, + Name = "MyTestIdentityProvider", + TokenEndpoint = "https://validIssuer.com/TokenEndpoint", + ValidIssuer = "https://validIssuer.com/" + }; + + _userManagerMock.Setup(x => x.GetSsoProviderById(ssoProviderId, It.IsAny())) + .ReturnsAsync( () => ssoProvider); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await _singleSignOn.ExchangeAuthorisationToken(ssoProviderId, code, CancellationToken.None); + }); + } + + [Test] + public void ExchangeAuthorisationToken_WhenOpenIdConfigurationReturnsEmptyString_ThrowsNullReferenceException() + { + //Arrange + var ssoProviderId = 123; + var code = "21kj345ghl2jk13b4"; + + var ssoProvider = new SsoProvider + { + Id = ssoProviderId, + AuthorizationEndpoint = "https://validIssuer.com/authorisationEndPoint", + ClientId = "clientId", + ClientSecret = "clientSecret", + Deleted = false, + IsPublic = true, + Name = "MyTestIdentityProvider", + TokenEndpoint = "https://validIssuer.com/TokenEndpoint", + ValidIssuer = "https://validIssuer.com/" + }; + + _userManagerMock.Setup(x => x.GetSsoProviderById(ssoProviderId, It.IsAny())) + .ReturnsAsync(() => ssoProvider); + + var httpResponseMessage = new HttpResponseMessage + { + Content = new StringContent("{\"id_token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"}") + }; + + _httpClientFacadeMock.Setup(x => x.SendAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(() => httpResponseMessage); + _httpClientFacadeMock.Setup(x => x.GetStringAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(() => ""); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await _singleSignOn.ExchangeAuthorisationToken(ssoProviderId, code, CancellationToken.None); + }); + } + + [Test] + public void ExchangeAuthorisationToken_WhenKeyIsInCorrect_ThrowsSignatureNotFoundExcpetion() + { + //Arrange + var ssoProviderId = 123; + var code = "21kj345ghl2jk13b4"; + + var ssoProvider = new SsoProvider + { + Id = ssoProviderId, + AuthorizationEndpoint = "https://validIssuer.com/authorisationEndPoint", + ClientId = "clientId", + ClientSecret = "clientSecret", + Deleted = false, + IsPublic = true, + Name = "MyTestIdentityProvider", + TokenEndpoint = "https://validIssuer.com/TokenEndpoint", + ValidIssuer = "https://validIssuer.com/" + }; + + _userManagerMock.Setup(x => x.GetSsoProviderById(ssoProviderId, It.IsAny())) + .ReturnsAsync(() => ssoProvider); + + var httpResponseMessage = new HttpResponseMessage + { + //note: This JWT will expire 2130-07-05T08:43:33.330Z. + Content = new StringContent("{\"id_token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3ZhbGlkSXNzdWVyLmNvbS8iLCJpYXQiOjE3MjAxNjkwMTMsImV4cCI6NTA2NTE0NTAxMywiYXVkIjoiY2xpZW50SWQiLCJzdWIiOiI2OTg0NzMyNDExIn0.YSzsnhkhZEyz1SfRQxNIQDv_7tzS-NxXqVKqvs3R308\"}") + }; + + _httpClientFacadeMock.Setup(x => x.SendAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(() => httpResponseMessage); + + var openIdConfiguration = new OpenIdConfiguration + { + JwksUri = "https://test.uri/jwks" + }.ToJson(); + + _httpClientFacadeMock.Setup(x => x.GetStringAsync(It.Is(uri => uri.AbsoluteUri.ToString().Equals("https://validissuer.com/.well-known/openid-configuration")), It.IsAny())) + .ReturnsAsync(() => openIdConfiguration); + + var openIdKeys = "{}"; + + _httpClientFacadeMock.Setup(x => x.GetStringAsync(It.Is(uri => uri.AbsoluteUri.ToString().Equals("https://test.uri/jwks")), It.IsAny())) + .ReturnsAsync(() => openIdKeys); + + _singleSignOn.ManualKey = "IncorrectKey"; + + //Act & Assert + Assert.ThrowsAsync( async () => { var result = await _singleSignOn.ExchangeAuthorisationToken(ssoProviderId, code, CancellationToken.None); }); + } + + [Test] + public async Task ExchangeAuthorisationToken_WhenValidJwt_ReturnsSubjectIdAsSsoUserId() + { + //Arrange + var ssoProviderId = 123; + var code = "21kj345ghl2jk13b4"; + + var ssoProvider = new SsoProvider + { + Id = ssoProviderId, + AuthorizationEndpoint = "https://validIssuer.com/authorisationEndPoint", + ClientId = "clientId", + ClientSecret = "clientSecret", + Deleted = false, + IsPublic = true, + Name = "MyTestIdentityProvider", + TokenEndpoint = "https://validIssuer.com/TokenEndpoint", + ValidIssuer = "https://validIssuer.com/" + }; + + _userManagerMock.Setup(x => x.GetSsoProviderById(ssoProviderId, It.IsAny())) + .ReturnsAsync(() => ssoProvider); + + var httpResponseMessage = new HttpResponseMessage + { + //note: This JWT will expire 2130-07-05T08:43:33.330Z. + Content = new StringContent("{\"id_token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3ZhbGlkSXNzdWVyLmNvbS8iLCJpYXQiOjE3MjAxNjkwMTMsImV4cCI6NTA2NTE0NTAxMywiYXVkIjoiY2xpZW50SWQiLCJzdWIiOiI2OTg0NzMyNDExIn0.YSzsnhkhZEyz1SfRQxNIQDv_7tzS-NxXqVKqvs3R308\"}") + }; + + _httpClientFacadeMock.Setup(x => x.SendAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(() => httpResponseMessage); + + var openIdConfiguration = new OpenIdConfiguration + { + JwksUri = "https://test.uri/jwks" + }.ToJson(); + + _httpClientFacadeMock.Setup(x => x.GetStringAsync(It.Is(uri => uri.AbsoluteUri.ToString().Equals("https://validissuer.com/.well-known/openid-configuration")), It.IsAny())) + .ReturnsAsync(() => openIdConfiguration); + + var openIdKeys = "{}"; + + _httpClientFacadeMock.Setup(x => x.GetStringAsync(It.Is(uri => uri.AbsoluteUri.ToString().Equals("https://test.uri/jwks")), It.IsAny())) + .ReturnsAsync(() => openIdKeys); + + _singleSignOn.ManualKey = "qwertyuiopasdfghjklzxcvbnm123456"; + + //Act + var result = await _singleSignOn.ExchangeAuthorisationToken(ssoProviderId, code, CancellationToken.None); + + //Assert + Assert.That(result, Is.EqualTo("6984732411")); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/SingleSignOnTestBase.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/SingleSignOnTestBase.cs new file mode 100644 index 0000000..36f7b26 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/SingleSignOnTestBase.cs @@ -0,0 +1,22 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using eSuite.API.SingleSignOn; +using Moq; + +namespace eSuite.API.UnitTests.SingleSignOn.SingleSignOn; + +public class SingleSignOnTestBase : TestBase +{ + protected API.SingleSignOn.SingleSignOn _singleSignOn = null!; + protected Mock _userManagerMock = null!; + protected Mock _httpClientFacadeMock = null!; + + public override async Task Setup() + { + await base.Setup(); + _userManagerMock = new Mock(); + _httpClientFacadeMock = new Mock(); + + _singleSignOn = new API.SingleSignOn.SingleSignOn(_userManagerMock.Object, _configuration, _httpClientFacadeMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/StartSingleSignOnUnitTests.cs b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/StartSingleSignOnUnitTests.cs new file mode 100644 index 0000000..fcb299b --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/SingleSignOn/SingleSignOn/StartSingleSignOnUnitTests.cs @@ -0,0 +1,89 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.UserManager; +using Moq; +using NUnit.Framework; + +namespace eSuite.API.UnitTests.SingleSignOn.SingleSignOn; + +[TestFixture] +public class StartSingleSignOnUnitTests : SingleSignOnTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task StartSingleSignOn_WhenNonSsoEmailProvided_ReturnsEmptyString() + { + //Arrange + var email = "nonsso@let.me.in"; + + //Act + var result = await _singleSignOn.StartSingleSignOn(email, CancellationToken.None); + + //Assert + Assert.That(result, Is.Empty); + } + + [Test] + public async Task StartSingleSignOn_WhenSsoEmailProvided_ReturnsExpectedAuthUrl() + { + //Arrange + var email = "ssoUser@myemail.provider"; + var redirectUri = "https://esuite.test"; + + var ssoProvider = new SsoProvider + { + Id = 10, + AuthorizationEndpoint = "https://myAuthProvider.com/auth", + ClientId = "testClientId" + }; + + _userManagerMock.Setup(x => x.GetSsoProviderForEmail(email, It.IsAny())).ReturnsAsync(ssoProvider); + + //Act + var result = await _singleSignOn.StartSingleSignOn(email, CancellationToken.None); + + //Assert + Assert.That( result, Is.EqualTo($"{ssoProvider.AuthorizationEndpoint}?response_type=code&client_id={ssoProvider.ClientId}&redirect_uri={redirectUri}/account/auth/{ssoProvider.Id}&scope=openid")); + } + + [Test] + public Task StartSingleSignOn_WhenInvalidSsoIdProvided_ThrowsNotFoundException() + { + //Arrange + var ssoProviderId = 12345; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + var result = await _singleSignOn.StartSingleSignOn(ssoProviderId, CancellationToken.None); + }); + return Task.CompletedTask; + } + + [Test] + public async Task StartSingleSignOn_WhenValidSsoIdProvided_ReturnsExpectedAuthUrl() + { + //Arrange + var ssoProviderId = 54321; + var redirectUri = "https://esuite.test"; + + var ssoProvider = new SsoProvider + { + Id = 10, + AuthorizationEndpoint = "https://myAuthProvider.com/auth", + ClientId = "testClientId" + }; + + _userManagerMock.Setup(x => x.GetSsoProviderById(ssoProviderId, It.IsAny())).ReturnsAsync(ssoProvider); + + //Act + var result = await _singleSignOn.StartSingleSignOn(ssoProviderId, CancellationToken.None); + + //Assert + Assert.That(result, Is.EqualTo($"{ssoProvider.AuthorizationEndpoint}?response_type=code&client_id={ssoProvider.ClientId}&redirect_uri={redirectUri}/account/auth/{ssoProvider.Id}&scope=openid")); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API.UnitTests/e-suite.API.Common.UnitTests.csproj b/e-suite.API/eSuite.API.UnitTests/e-suite.API.Common.UnitTests.csproj new file mode 100644 index 0000000..66bddb9 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/e-suite.API.Common.UnitTests.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + e_suite.API.Common.UnitTests + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.API/eSuite.API.UnitTests/eSuite.API.UnitTests.csproj b/e-suite.API/eSuite.API.UnitTests/eSuite.API.UnitTests.csproj new file mode 100644 index 0000000..02f6e53 --- /dev/null +++ b/e-suite.API/eSuite.API.UnitTests/eSuite.API.UnitTests.csproj @@ -0,0 +1,32 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/e-suite.API/eSuite.API.sln b/e-suite.API/eSuite.API.sln new file mode 100644 index 0000000..3f39465 --- /dev/null +++ b/e-suite.API/eSuite.API.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "eSuite.API", "eSuite.API\eSuite.API.csproj", "{4A704FA7-4E3A-4CFA-B043-434A0C49AF89}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{9B943FFF-4CEA-4206-BFD4-2450317733C1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{27EA902C-3CD0-4A8F-BA75-8D1AF87902AC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "eSuite.API.UnitTests", "eSuite.API.UnitTests\eSuite.API.UnitTests.csproj", "{D64B6107-D791-4B90-BB3E-020DB5E77FC5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.Migrator", "e-suite.Database.Migrator\e-suite.Database.Migrator.csproj", "{734A4BF4-0DC1-41F7-B671-DE0E32B80EC8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{967FBBE8-3E56-46D9-A486-2750ED5A5A60}" + ProjectSection(SolutionItems) = preProject + azure-pipelines.yml = azure-pipelines.yml + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4A704FA7-4E3A-4CFA-B043-434A0C49AF89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A704FA7-4E3A-4CFA-B043-434A0C49AF89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A704FA7-4E3A-4CFA-B043-434A0C49AF89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A704FA7-4E3A-4CFA-B043-434A0C49AF89}.Release|Any CPU.Build.0 = Release|Any CPU + {D64B6107-D791-4B90-BB3E-020DB5E77FC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D64B6107-D791-4B90-BB3E-020DB5E77FC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D64B6107-D791-4B90-BB3E-020DB5E77FC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D64B6107-D791-4B90-BB3E-020DB5E77FC5}.Release|Any CPU.Build.0 = Release|Any CPU + {734A4BF4-0DC1-41F7-B671-DE0E32B80EC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {734A4BF4-0DC1-41F7-B671-DE0E32B80EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {734A4BF4-0DC1-41F7-B671-DE0E32B80EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {734A4BF4-0DC1-41F7-B671-DE0E32B80EC8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {27EA902C-3CD0-4A8F-BA75-8D1AF87902AC} = {9B943FFF-4CEA-4206-BFD4-2450317733C1} + {D64B6107-D791-4B90-BB3E-020DB5E77FC5} = {27EA902C-3CD0-4A8F-BA75-8D1AF87902AC} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C5175258-F776-4FF9-A9EE-386312E47061} + EndGlobalSection +EndGlobal diff --git a/e-suite.API/eSuite.API/.gitignore b/e-suite.API/eSuite.API/.gitignore new file mode 100644 index 0000000..c003733 --- /dev/null +++ b/e-suite.API/eSuite.API/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/e-suite.API/eSuite.API/Controllers/AccountController.cs b/e-suite.API/eSuite.API/Controllers/AccountController.cs new file mode 100644 index 0000000..8c91f4a --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/AccountController.cs @@ -0,0 +1,382 @@ +using System.Text.Json; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Service.Sentinel; +using eSuite.API.Extensions; +using eSuite.API.security; +using eSuite.API.SingleSignOn; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This MVC controller is used to support all user interactions when logging in and out of the system, including profile updates. +/// +[Route("/[controller]")] +[ApiExplorerSettings(IgnoreApi = true)] +public class AccountController : ESuiteController +{ + private readonly IUserManager _userManager; + private readonly ISentinel _sentinel; + private readonly ISingleSignOn _singleSignOn; + private readonly ICookieManager _cookieManager; + + /// + /// Default constructor used to inject dependencies + /// + /// + /// + /// + /// + public AccountController(IUserManager userManager, ISentinel sentinel, ISingleSignOn singleSignOn, ICookieManager cookieManager) + { + _userManager = userManager; + _sentinel = sentinel; + _singleSignOn = singleSignOn; + _cookieManager = cookieManager; + } + + private const string AccountProfileUrl = "~/account/profile"; + private const string RootUrl = "/"; + private const string ProfileUrl = "~/profile"; + + /// + /// Returns the login page for the system + /// + /// + /// + /// + [Route("login")] + [AllowAnonymous] + [AccessKey(SecurityAccess.Everyone)] + [HttpGet] + public async Task LoginGet(Login? login, CancellationToken cancellationToken) + { + var ssoId = await _cookieManager.GetSsoIdFromSsoIdCookie(Request); + if (ssoId.HasValue) + { + await _cookieManager.DeleteSsoIdCookie(Response); + var url = await _singleSignOn.StartSingleSignOn(ssoId.Value, cancellationToken); + return Redirect(url); + } + + login ??= new Login(); + + return LoginView(login); + } + + private ViewResult LoginView(Login? login) + { + return View("Login", login); + } + + /// + /// Used for processing the login attempts + /// + /// + /// + /// + [Route("login")] + [AllowAnonymous] + [AccessKey(SecurityAccess.Everyone)] + [HttpPost] + [ValidateAntiForgeryToken] + public async Task LoginPost(Login login, CancellationToken cancellationToken) + { + if (string.IsNullOrWhiteSpace(login.Password)) + { + var url = await _singleSignOn.StartSingleSignOn(login.Email, cancellationToken); + if (!string.IsNullOrWhiteSpace(url)) + return Redirect(url); + + if (login.ForgotPassword) + { + await _userManager.ForgotPassword(login.Email, cancellationToken); + } + + return LoginView(login); + } + + if (login.ForgotPassword) + { + await _userManager.ForgotPassword(login.Email, cancellationToken); + return LoginView(login); + } + + var loginResponse = await _userManager.Login(login, cancellationToken); + ViewBag.loginResponse = loginResponse.Result; + switch (loginResponse.Result) + { + case LoginResult.Success: + await _cookieManager.CreateSessionCookie(Response, loginResponse); + + return Redirect("/"); + case LoginResult.EmailNotConfirmed: + case LoginResult.TwoFactorAuthenticationRemovalRequested: + case LoginResult.TwoFactorAuthenticationCodeRequired: + case LoginResult.TwoFactorAuthenticationCodeIncorrect: + return LoginView(login); + case LoginResult.Failed: + default: + await _sentinel.LogBadRequest(this, cancellationToken); + return LoginView(login); + } + } + + /// + /// Logs a user out of the system and tidies up any cookies. + /// + /// + /// + [Route("logout")] + [HttpGet] + [AllowAnonymous] +#pragma warning disable IDE0060 // Remove unused parameter cancellationToken - used here as I want this parameter on all controller methods. + public async Task Logout(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + await _cookieManager.DeleteSessionCookie(Response); + await _cookieManager.DeleteSsoIdCookie(Response); + return Redirect("~/"); + } + + /// + /// Called by an identity provider when processing an OAuth2 identity request. + /// + /// + /// + /// + /// + /// + /// + /// + [Route("auth/{ssoId}")] + [HttpGet] + [AllowAnonymous] +#pragma warning disable IDE0060 // Remove unused parameter + // ReSharper disable once IdentifierTypo + public async Task Auth([FromRoute] long ssoId, [FromQuery] string code, [FromQuery] string scope, [FromQuery] string authuser, [FromQuery] string prompt, CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + var ssoUserId = await _singleSignOn.ExchangeAuthorisationToken(ssoId, code, cancellationToken); + + var cookieLink = await _cookieManager.GetUserIdFromLinkCookie(Request, cancellationToken); + + if (cookieLink?.User != null) + { + await _cookieManager.DeleteLinkCookie(Response); + + //Creating my own Audit details as the JWT isn't present when being called from an outside source + var auditUserDetails = new AuditUserDetails + { + UserId = cookieLink.User.Id, + UserDisplayName = cookieLink.User.DisplayName + }; + + await _userManager.LinkSsoProfileToUser(auditUserDetails, cookieLink.User, ssoId, ssoUserId, cookieLink.LinkType == LinkType.NewUser , cancellationToken); + + if (cookieLink.LinkType == LinkType.Profile) + return Redirect(ProfileUrl); + } + + var loginResponse = await _userManager.LoginSso(ssoId, ssoUserId, cancellationToken); + + switch (loginResponse.Result) + { + case LoginResult.Success: + await _cookieManager.CreateSessionCookie(Response, loginResponse); + await _cookieManager.CreateSsoIdCookie(Response, ssoId); + + return Redirect("~/"); + case LoginResult.EmailNotConfirmed: + case LoginResult.TwoFactorAuthenticationRemovalRequested: + case LoginResult.TwoFactorAuthenticationCodeRequired: + case LoginResult.TwoFactorAuthenticationCodeIncorrect: + return Redirect("~/"); + case LoginResult.Failed: + default: + await _sentinel.LogBadRequest(this, cancellationToken); + return Redirect("~/"); + } + } + + /// + /// Get a new token to replace your current token. + /// + /// e-suite authentication tokens are valid for a limited amount of time. To gain more time on your user session you will need to exchange your token for a new one. + /// + [Route("refreshToken")] + [HttpGet] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task RefreshToken(CancellationToken cancellationToken = default!) + { + var id = User.GeneralIdRef(); + var loginResponse = await _userManager.RefreshToken(id, cancellationToken); + + await _cookieManager.CreateSessionCookie(Response, loginResponse); + + return Ok(); + } + + /// + /// Page used for making alterations to a users profile. + /// + /// + /// + [Route("profile")] + [HttpGet] + [AccessKey(SecurityAccess.Everyone)] + public async Task ProfileGet(CancellationToken cancellationToken) + { + var profile = await _userManager.GetProfile(User.Email(), cancellationToken); + var userProfile = profile.ToUserProfile(); + + return View("Profile", userProfile); + } + + /// + /// Used to make updates to a users profile. + /// + /// + /// + /// + [Route("profile")] + [AccessKey(SecurityAccess.Everyone)] + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ProfilePost(Models.UserProfile userProfile, CancellationToken cancellationToken) + { + var updatedUserProfile = new UpdatedUserProfile + { + Email = User.Email(), + Password = userProfile.Password ?? string.Empty, + FirstName = userProfile.FirstName ?? string.Empty, + MiddleNames = userProfile.MiddleNames ?? string.Empty, + LastName = userProfile.LastName ?? string.Empty, + SecurityCode = userProfile.SecurityCode ?? string.Empty, + UsingTwoFactorAuthentication = userProfile.UsingTwoFactorAuthentication + }; + + await _userManager.UpdateProfile(AuditUserDetails, User.Email(), updatedUserProfile, cancellationToken); + + var profile = await _userManager.GetProfile(User.Email(), cancellationToken); + + var id = User.GeneralIdRef(); + + if (profile.DomainSsoProviderId == null) + { + if (profile.SsoProviderId != userProfile.SsoProviderId) + { + if (userProfile.SsoProviderId != -1) + { + var url = await _singleSignOn.StartSingleSignOn(userProfile.SsoProviderId, cancellationToken); + if (!string.IsNullOrWhiteSpace(url)) + { + await _cookieManager.CreateProfileLinkCookie(Response, AuditUserDetails, id, cancellationToken); + + return Redirect(url); + } + } + else + { + await _userManager.TurnOfSsoForUser(AuditUserDetails, id, cancellationToken); + } + } + } + + return Redirect(AccountProfileUrl); + } + + /// + /// Page used for making alterations to a users profile. + /// + /// + /// + /// + [Route("confirmaccount/{token}")] + [HttpGet] + [AllowAnonymous] + [AccessKey(SecurityAccess.Everyone)] + public async Task ConfirmAccountGet([FromRoute] string token, CancellationToken cancellationToken) + { + var emailActionToken = DecodeToken(token); + + var profile = await _userManager.GetProfile(emailActionToken?.Email!, cancellationToken); + var userProfile = profile.ToConfirmEmailAccount(); + + return View("ConfirmAccount", userProfile); + } + + private static EmailActionToken? DecodeToken(string token) + { + var jsonString = Convert.FromBase64String(token); + var emailActionToken = JsonSerializer.Deserialize(jsonString); + return emailActionToken; + } + + /// + /// Used to make updates to a users profile. + /// + /// + /// + /// + /// + [Route("confirmaccount/{token}")] + [AllowAnonymous] + [AccessKey(SecurityAccess.Everyone)] + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ConfirmAccountPost( + Models.ConfirmEmailAccount userProfile, + [FromRoute] string token, + CancellationToken cancellationToken + ) + { + var emailActionToken = DecodeToken(token); + var user = await _userManager.GetUserByEmailAsync(emailActionToken?.Email!, cancellationToken) ?? + throw new NotFoundException("User not found"); + + var auditUserDetails = new AuditUserDetails + { + UserId = user.Id, + UserDisplayName = user.DisplayName + }; + + + if (user.Domain.SsoProviderId is not null || userProfile.SsoProviderId != -1) + { + var url = await _singleSignOn.StartSingleSignOn(user.Domain.SsoProviderId ?? userProfile.SsoProviderId, cancellationToken); + if (!string.IsNullOrWhiteSpace(url)) + { + await _cookieManager.CreateNewUserLinkCookie(Response, auditUserDetails, user.ToGeneralIdRef()!, + cancellationToken); + + return Redirect(url); + } + } + else + { + await _userManager.TurnOfSsoForUser(auditUserDetails, user.ToGeneralIdRef()!, cancellationToken); + + var userAuthenticationDetails = new UserAuthenticationDetails + { + Id = user.ToGeneralIdRef()!, + Password = userProfile.Password ?? string.Empty, + SecurityCode = userProfile.SecurityCode ?? string.Empty, + UsingTwoFactorAuthentication = userProfile.UsingTwoFactorAuthentication + }; + + await _userManager.SetAuthentication(auditUserDetails, userAuthenticationDetails, true, cancellationToken); + } + + return Redirect(RootUrl); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/AuditController.cs b/e-suite.API/eSuite.API/Controllers/AuditController.cs new file mode 100644 index 0000000..86d79d7 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/AuditController.cs @@ -0,0 +1,41 @@ +using e_suite.API.Common; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Methods used for viewing the audit trail +/// +[Route("api/[controller]")] +[ApiController] +public class AuditController : ESuiteControllerBase +{ + private readonly IAuditLog _auditLog; + + /// + /// Constructor for the Audit Controller. + /// + /// + public AuditController(IAuditLog auditLog) + { + _auditLog = auditLog; + } + + /// + /// Returns the audit entries for the system + /// + /// Returns all audit log entries + [Route("log")] + [HttpGet] + [AccessKey(SecurityAccess.ViewAuditLog)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task Get([FromQuery] Paging paging, [FromQuery] string? logEntry, [FromQuery] bool primaryOnly, CancellationToken cancellationToken = default!) + { + var result = await _auditLog.GetAuditLogEntries(paging, logEntry, primaryOnly, cancellationToken); + return Ok(result); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/AuthenticationController.cs b/e-suite.API/eSuite.API/Controllers/AuthenticationController.cs new file mode 100644 index 0000000..caa5afe --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/AuthenticationController.cs @@ -0,0 +1,213 @@ +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Service.Sentinel; +using eSuite.API.Models; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This part of the API is responsible for creating and maintaining user sessions within e-suite +/// +[Route("api/[controller]")] +[ApiController] +public class AuthenticationController : ESuiteControllerBase +{ + private readonly IUserManager _userManager; + private readonly ISentinel _sentinel; + + private const string AccessDeniedText = "Access denied"; + private const string LoginAcceptedText = "Login accepted"; + + /// + /// Default constructor used for dependency injection + /// + /// + /// + public AuthenticationController(IUserManager userManager, ISentinel sentinel) + { + _userManager = userManager; + _sentinel = sentinel; + } + + /// + /// Request an password recovery email is sent + /// + /// A password recovery email allows someone to gain access to the system after they have lost their password. It will allow them to reset their password. + /// + [Route("forgotPassword")] + [HttpPost] + [AccessKey(SecurityAccess.Everyone)] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ForgotPassword( + [FromBody] EmailAddress forgotPasswordRequest, + CancellationToken cancellationToken = default! + ) + { + try + { + var securityResult = await _sentinel.CheckSecurity(this, cancellationToken); + if (securityResult != null) + return securityResult; + + await _userManager.ForgotPassword(forgotPasswordRequest.Email, cancellationToken); + + return Ok(); + } + catch (NotFoundException) + { + await _sentinel.LogBadRequest(this, cancellationToken); + throw; + } + catch (EmailNotConfirmedException) + { + await _sentinel.LogBadRequest(this, cancellationToken); + return Unauthorized(new ProblemDetails + { + Title = AccessDeniedText, + Detail = "Email not confirmed" + }); + } + } + + /// + /// Login with username, password and optionally Two Factor Authentication code + /// + /// Log into e-suite using username, password and optionally Two factor Authentication. This call can also be used to attempt to request two factor authentication is disabled. + /// This is my example + /// + /// Authentication successful. The "instance" property will contain the token to include to access secure api calls + /// Username and password accepted. Two factor (Tfa) security code required, or request to disable Tfa processed. See the detail property. + /// Authentication is unsuccessful + [Route("login")] + [HttpPost] + [AccessKey(SecurityAccess.Everyone)] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SuccessfulLogin))] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [Produces("application/json")] + [Obsolete("Login is dealt with via SSO now. Only username and password auth will work with this call. Will be replaced with user created API Keys.")] + public async Task Login([FromBody] Login login, CancellationToken cancellationToken = default!) + { + var securityResult = await _sentinel.CheckSecurity(this, cancellationToken); + if (securityResult != null) + return securityResult; + + var loginResponse = await _userManager.Login(login, cancellationToken); + switch (loginResponse.Result) + { + case LoginResult.EmailNotConfirmed: + return Unauthorized(new ProblemDetails + { + Title = AccessDeniedText, + Detail = "Email not confirmed" + }); + case LoginResult.TwoFactorAuthenticationRemovalRequested: + return Accepted(new ProblemDetails + { + Title = LoginAcceptedText, + Detail = "Request to remove two factor authentication accepted" + }); + case LoginResult.TwoFactorAuthenticationCodeRequired: + return Accepted(new ProblemDetails + { + Title = LoginAcceptedText, + Detail = "Please supply Two Factor Authentication code" + }); + case LoginResult.TwoFactorAuthenticationCodeIncorrect: + await _sentinel.LogBadRequest(this, cancellationToken); + return Unauthorized(new ProblemDetails + { + Title = AccessDeniedText, + Detail = "Incorrect authorisation code" + + }); + case LoginResult.Success: + return Ok(new SuccessfulLogin + { + Title = LoginAcceptedText, + Token = loginResponse.Token + }); + case LoginResult.Failed: + default: + await _sentinel.LogBadRequest(this, cancellationToken); + return Unauthorized(new ProblemDetails + { + Title = AccessDeniedText, Detail = "Email and/or Password has been entered incorrectly" + }); + } + } + + /// + /// Call this to complete the action for an email with an action link. + /// + /// There are several functions in the system that will result in an email being sent to the user with a link so they can confirm. Currently these are to for a forgotten password, to disable the two factor authentication and for a new user to confirm their e-mail + /// + /// + /// + [Route("completeEmailAction")] + [HttpPost] + [AccessKey(SecurityAccess.Everyone)] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + public async Task CompleteEmailAction( + [FromBody] EmailActionToken token, + CancellationToken cancellationToken = default! + ) + { + var securityResult = await _sentinel.CheckSecurity(this, cancellationToken); + if (securityResult != null) + return securityResult; + + try + { + await _userManager.CompleteEmailAction(token, cancellationToken); + return Ok(); + } + catch (TokenInvalidException) + { + await _sentinel.LogBadRequest(this, cancellationToken); + throw; + } + catch (InvalidEmailException) + { + await _sentinel.LogBadRequest(this, cancellationToken); + throw; + } + } + + /// + /// Get a new token to replace your current token. + /// + /// e-suite authentication tokens are valid for a limited amount of time. To gain more time on your user session you will need to exchange your token for a new one. + /// + [Route("refreshToken")] + [HttpGet] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task RefreshToken(CancellationToken cancellationToken = default!) + { + var userId = User.GeneralIdRef(); + + var loginResponse = await _userManager.RefreshToken(userId, cancellationToken); + + if (loginResponse.Result != LoginResult.Success) + return Unauthorized(new ProblemDetails + { + Title = AccessDeniedText, + Detail = "Username or Password incorrect" + }); + + return Ok(new SuccessfulLogin { Title = "Access Granted", Token = loginResponse.Token }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/BlockedIPsController.cs b/e-suite.API/eSuite.API/Controllers/BlockedIPsController.cs new file mode 100644 index 0000000..fd79881 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/BlockedIPsController.cs @@ -0,0 +1,61 @@ +using e_suite.API.Common; +using e_suite.Utilities.Pagination; +using eSuite.API.Models; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This part of the API is responsible for maintaining blocked IPs within e-suite +/// +[Route("api/[controller]")] +[ApiController] +public class BlockedIPsController : ESuiteControllerBase + { + private readonly IBlockedIPsManager _blockedIPsManager; + /// + /// Default constructor used for dependency injection + /// + public BlockedIPsController(IBlockedIPsManager blockedIPsManager) + { + _blockedIPsManager = blockedIPsManager; + } + + /// + /// Returns a list of all the blocked IP address in the system + /// + /// This returns all the blocked IP address in the system. + /// + /// + /// + [Route("blockedIPs")] + [HttpGet] + [AccessKey(SecurityAccess.ViewBlockedIPAddresses)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task Get([FromQuery] Paging paging, CancellationToken cancellationToken = default!) + { + var result = await _blockedIPsManager.GetBlockedIPs(paging, cancellationToken); + return Ok(result); + } + + /// + /// Unblock an IP address + /// + /// + /// + /// + [Route("delete")] + [HttpDelete] + [AccessKey(SecurityAccess.UnlockIPAddress)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task Delete([FromBody] BlockedIPAddress blockedIPAddress, CancellationToken cancellationToken) + { + await _blockedIPsManager.UnblockIPAddress(AuditUserDetails, blockedIPAddress.IpAddress, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/CustomFieldsController.cs b/e-suite.API/eSuite.API/Controllers/CustomFieldsController.cs new file mode 100644 index 0000000..5c349af --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/CustomFieldsController.cs @@ -0,0 +1,127 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Custom fields manager is responsible for managing Custom fields within e-suite. +/// +[Route("api/[controller]")] +[ApiController] +public class CustomFieldsController : ESuiteControllerBase +{ + private readonly ICustomFieldManager _customFieldManager; + /// + /// Constructor for the FieldController + /// + /// + public CustomFieldsController(ICustomFieldManager customFieldManager) + { + _customFieldManager = customFieldManager; + } + + /// + /// Returns a list of all the fields in the system + /// + /// This returns all the fields in the system that are not soft deleted. + [Route("fields")] + [HttpGet] + [AccessKey(SecurityAccess.ViewField)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetFields( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _customFieldManager.GetFieldsAsync(paging, cancellationToken); + return Ok(result); + } + + /// + /// Gets the custom field by and id + /// + /// + /// + /// + [Route("field")] + [HttpGet] + [AccessKey(SecurityAccess.ViewField)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task GetField( + [FromQuery] GeneralIdRef genralIdRef, + CancellationToken cancellationToken = default! + ) + { + var field = await _customFieldManager.GetFieldAsync(genralIdRef, cancellationToken); + return Ok(field); + } + + /// + /// Create a custom field + /// + /// + /// + /// + [Route("field")] + [HttpPost] + [AccessKey(SecurityAccess.AddField)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateField( + [FromBody] CreateCustomField customField, + CancellationToken cancellationToken = default! + ) + { + await _customFieldManager.CreateFieldAsync(AuditUserDetails, customField, cancellationToken); + return Ok(); + } + + /// + /// Updates the values of a created Custom field + /// + /// + /// + /// + [Route("field")] + [HttpPut] + [AccessKey(SecurityAccess.EditField)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task EditField( + [FromBody] EditCustomFields customFields, + CancellationToken cancellationToken = default! + ) + { + await _customFieldManager.EditFieldAsync(AuditUserDetails, customFields, cancellationToken); + return Ok(); + } + + /// + /// Delete a custom field by giving a Id + /// + /// + /// + /// + [Route("field")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteField)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task DeleteField( + [FromBody] GeneralIdRef id, + CancellationToken cancellationToken = default! + ) + { + await _customFieldManager.DeleteFieldAsync(AuditUserDetails, id, cancellationToken); + return Ok(); + } +} diff --git a/e-suite.API/eSuite.API/Controllers/DomainController.cs b/e-suite.API/eSuite.API/Controllers/DomainController.cs new file mode 100644 index 0000000..e736f66 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/DomainController.cs @@ -0,0 +1,129 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Methods for interacting with Domains +/// +[Route("api/[controller]")] +public class DomainController : ESuiteControllerBase +{ + private readonly IDomainManager _domainManager; + + /// + /// Constructor for the Domain Controller + /// + /// + public DomainController(IDomainManager domainManager) + { + _domainManager = domainManager; + } + + /// + /// Get list of all domains + /// + /// + /// + /// + [Route("domains")] + [HttpGet] + [AccessKey(SecurityAccess.ViewDomain)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetDomains( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _domainManager.GetDomainsAsync(paging, cancellationToken); + return Ok(result); + } + + /// + /// Get details of domain + /// + /// + /// + /// Returns the FormTemplate with the corresponding Id + [Route("domain")] + [HttpGet] + [AccessKey(SecurityAccess.ViewDomain)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetDomain( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var form = await _domainManager.GetDomainAsync(generalIdRef, cancellationToken); + return Ok(form); + } + + /// + /// Create Domain + /// + /// + /// + /// + [Route("domain")] + [HttpPost] + [AccessKey(SecurityAccess.AddDomain)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task CreateDomain( + [FromBody] CreateDomain createDomain, + CancellationToken cancellationToken = default! + ) + { + await _domainManager.CreateDomainAsync(AuditUserDetails, createDomain, cancellationToken); + return Ok(); + } + + /// + /// Edit domain + /// + /// + /// + [Route("domain")] + [HttpPut] + [AccessKey(SecurityAccess.EditDomain)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task EditDomain( + [FromBody] EditDomain editFormTemplate, + CancellationToken cancellationToken = default! + ) + { + await _domainManager.EditDomainAsync(AuditUserDetails, editFormTemplate, cancellationToken); + return Ok(); + } + + /// + /// Delete a formTemplate with all of its versions by providing GeneralIdRef of the FormTemplate + /// + /// + /// + [Route("domain")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteDomain)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteDomain( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _domainManager.DeleteDomainAsync(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/ExceptionLogsController.cs b/e-suite.API/eSuite.API/Controllers/ExceptionLogsController.cs new file mode 100644 index 0000000..1b0c289 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/ExceptionLogsController.cs @@ -0,0 +1,42 @@ +using e_suite.API.Common; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This part of the API is responsible for maintaining Exception Logs within e-suite +/// +[Route("api/[controller]")] +[ApiController] +public class ExceptionLogsController : ESuiteControllerBase +{ + private readonly IExceptionLogManager _exceptionLogManager; + /// + /// Default constructor used for dependency injection + /// + public ExceptionLogsController(IExceptionLogManager exceptionLogManager) + { + _exceptionLogManager = exceptionLogManager; + } + + /// + /// Returns a list of all the exception logs in the system + /// + /// This returns all the exception logs in the system. + /// + /// + /// + [Route("exceptionlogs")] + [HttpGet] + [AccessKey(SecurityAccess.ViewErrorLogs)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task Get([FromQuery] Paging paging, CancellationToken cancellationToken = default!) + { + var result = await _exceptionLogManager.GetExceptionLogs(paging, cancellationToken); + return Ok(result); + } +} diff --git a/e-suite.API/eSuite.API/Controllers/FormsController.cs b/e-suite.API/eSuite.API/Controllers/FormsController.cs new file mode 100644 index 0000000..7d104f9 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/FormsController.cs @@ -0,0 +1,185 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// forms manager is responsible for managing custom forms within e-suite. +/// +[Route("api/[controller]")] +public class FormsController : ESuiteControllerBase +{ + private readonly IFormsManager _formsManager; + + /// + /// Constructor for the FormsController + /// Constructor for the FormsController + /// + /// + public FormsController(IFormsManager formsManager) + { + _formsManager = formsManager; + } + + /// + /// Gets all FormTemplates with latest version + /// + /// Collection of all FormTemplates + [Route("forms")] + [HttpGet] + [AccessKey(SecurityAccess.ViewFormTemplate)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetFormTemplates( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _formsManager.GetFormTemplatesAsync(paging, cancellationToken); + return Ok(result); + } + + /// + /// Get FormTemplate by supplying GeneralIdRef + /// + /// + /// + /// Returns the FormTemplate with the corresponding Id + [Route("form")] + [HttpGet] + [AccessKey(SecurityAccess.ViewFormTemplate)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetFormTemplate( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var form = await _formsManager.GetFormTemplateAsync(generalIdRef, cancellationToken); + return Ok(form); + } + + /// + /// Create FormTemplate + /// + /// + /// + [Route("form")] + [HttpPost] + [AccessKey(SecurityAccess.AddFormTemplate)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task CreateFormTemplate([FromBody] CreateFormTemplate createFormTemplate, CancellationToken cancellationToken = default!) + { + await _formsManager.CreateFormTemplateAsync(AuditUserDetails, createFormTemplate, cancellationToken); + return Ok(); + } + + /// + /// Edit FormTemplate + /// + /// + /// + [Route("form")] + [HttpPut] + [AccessKey(SecurityAccess.EditFormTemplate)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task EditFormTempalate([FromBody] EditFormTemplate editFormTemplate, CancellationToken cancellationToken = default!) + { + await _formsManager.EditFormTemplateAsync(AuditUserDetails, editFormTemplate, cancellationToken); + return Ok(); + } + + /// + /// Delete a formTemplate with all of its versions by providing GeneralIdRef of the FormTemplate + /// + /// + /// + [Route("form")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteFormTemplate)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteForm( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _formsManager.DeleteFormTemplateAsync(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } + + /// + /// Get FormTemplate by supplying GeneralIdRef + /// + /// + /// + /// Returns the FormTemplate with the corresponding Id + [Route("formInstance")] + [HttpGet] + [AccessKey(SecurityAccess.ViewFormInstance)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetFormInstance( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var form = await _formsManager.GetFormInstanceAsync(generalIdRef, cancellationToken); + return Ok(form); + } + + /// + /// Create an instance of a form based on a given version of a template + /// + /// + /// + /// + [Route("formInstance")] + [HttpPost] + [AccessKey(SecurityAccess.AddFormInstance)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task CreateFormInstance( + [FromBody] CreateFormInstance createFormInstance, + CancellationToken cancellationToken = default! + ) + { + var formInstanceGeneralIdRef = + await _formsManager.CreateFormInstanceAsync(AuditUserDetails, createFormInstance, cancellationToken); + return Ok(formInstanceGeneralIdRef); + } + + /// + /// Edit a Form Instance + /// + /// + /// + /// + [Route("formInstance")] + [HttpPut] + [AccessKey(SecurityAccess.EditFormInstance)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task EditFormInstance( + [FromBody] EditFormInstance editFormInstance, + CancellationToken cancellationToken = default! + ) + { + await _formsManager.EditFormInstanceAsync(AuditUserDetails, editFormInstance, cancellationToken); + return Ok(); + } +} diff --git a/e-suite.API/eSuite.API/Controllers/GlossariesController.cs b/e-suite.API/eSuite.API/Controllers/GlossariesController.cs new file mode 100644 index 0000000..e408453 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/GlossariesController.cs @@ -0,0 +1,98 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Controller for managing GlossaryItems within e-suite system +/// +[Route("api/[controller]")] +[ApiController] +public class GlossariesController : ESuiteControllerBase +{ + private readonly IGlossariesManager _glossariesManager; + + /// + /// Controller for the GlossaryManager + /// + /// + public GlossariesController(IGlossariesManager glossariesManager) + { + _glossariesManager = glossariesManager; + } + + /// + /// Used to retrieve the details of a given glossary item (does not include child items) + /// + /// + /// + /// Returns GlossaryItem with corresponding Id + [Route("glossaryItem")] + [HttpGet] + [AccessKey(SecurityAccess.ViewGlossary)] + public async Task Get( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var glossary = await _glossariesManager.GetGlossaryItem(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(glossary); + } + + /// + /// Used to create a new glossary list or add an item to an existing glossary list. + /// + /// + /// + [Route("glossaryItem")] + [HttpPost] + [AccessKey(SecurityAccess.AddGlossary)] + public async Task Post([FromBody] NewGlossaryItem glossaryItem, CancellationToken cancellationToken = default!) + { + await _glossariesManager.AddGlossaryItem(AuditUserDetails, glossaryItem, cancellationToken); + + return Ok(); + } + + + /// + /// Used to update an existing glossary item. + /// + /// + /// + [Route("glossaryItem")] + [HttpPut] + [AccessKey(SecurityAccess.EditGlossary)] + public async Task Put([FromBody] EditGlossaryItem glossaryItem, CancellationToken cancellationToken = default!) + { + await _glossariesManager.UpdateGlossaryItem(AuditUserDetails, glossaryItem, cancellationToken); + + return Ok(); + } + + /// + /// Delete an item from a glossary, or delete an entire glossary + /// + /// + /// + [Route("glossaryItem")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteGlossary)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task Delete( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _glossariesManager.DeleteGlossaryItem(AuditUserDetails, generalIdRef, cancellationToken); + + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/InternalMessagingController.cs b/e-suite.API/eSuite.API/Controllers/InternalMessagingController.cs new file mode 100644 index 0000000..b7664a9 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/InternalMessagingController.cs @@ -0,0 +1,144 @@ +using e_suite.Messaging.Common; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Internal API used to trigger messages that the scheduler sends. +/// +[Route("api/[controller]")] +public class InternalMessagingController : ESuiteControllerBase +{ + private readonly ISigmaImportMessageSender _sigmaImportMessageSender; + private readonly IDatabaseMessageSender _databaseMessageSender; + private readonly IEFlowSyncMessageSender _eFlowSyncMessageSender; + + /// + /// + /// + /// + /// + /// + public InternalMessagingController(ISigmaImportMessageSender sigmaImportMessageSender, IDatabaseMessageSender databaseMessageSender, IEFlowSyncMessageSender eFlowSyncMessageSender) + { + _sigmaImportMessageSender = sigmaImportMessageSender; + _databaseMessageSender = databaseMessageSender; + _eFlowSyncMessageSender = eFlowSyncMessageSender; + } + + /// + /// + /// + /// + [Route("PostImportGMGProfiles")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.ImportGMGProfiles)] +#pragma warning disable IDE0060 // Remove unused parameter + public Task PostImportGmgProfiles(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _sigmaImportMessageSender.PostImportGMGProfiles(); + return Task.CompletedTask; + } + + /// + /// + /// + /// + [Route("PostImportPrintSpecifications")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.ImportPrintSpecifications)] +#pragma warning disable IDE0060 // Remove unused parameter + public Task PostImportPrintSpecifications(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _sigmaImportMessageSender.PostImportPrintSpecifications(); + return Task.CompletedTask; + } + + /// + /// + /// + /// + [Route("PostClearOldEmailActions")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.ClearOldEmailActions)] +#pragma warning disable IDE0060 // Remove unused parameter + public Task PostClearOldEmailActions(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _databaseMessageSender.PostClearOldEmailActions(); + return Task.CompletedTask; + } + + /// + /// + /// + /// + [Route("PostClearOldPerformanceData")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.ClearOldPerformanceData)] +#pragma warning disable IDE0060 // Remove unused parameter + public Task PostClearOldPerformanceData(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _databaseMessageSender.PostClearOldPerformanceData(); + return Task.CompletedTask; + } + + /// + /// + /// + /// + [Route("PostClearOldSentinelData")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.ClearOldSentinelData)] +#pragma warning disable IDE0060 // Remove unused parameter + public Task PostClearOldSentinelData(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _databaseMessageSender.PostClearOldSentinelData(); + return Task.CompletedTask; + } + + /// + /// + /// + /// + [Route("PostClearOldSingleUserGuids")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.ClearOldSingleUserGuids)] +#pragma warning disable IDE0060 // Remove unused parameter + public Task PostClearOldSingleUserGuids(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _databaseMessageSender.PostClearOldSingleUserGuids(); + return Task.CompletedTask; + } + + /// + /// + /// + /// + /// + [Route("PostSyncEFlowPrinterCategories")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [AccessKey(SecurityAccess.SyncEFlowPrinterCategories)] //todo change this. +#pragma warning disable IDE0060 // Remove unused parameter + public Task SyncEFlowPrinterCategories(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/MailTemplatesController.cs b/e-suite.API/eSuite.API/Controllers/MailTemplatesController.cs new file mode 100644 index 0000000..ec496eb --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/MailTemplatesController.cs @@ -0,0 +1,88 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Mail templates are used when preparing emails that are sent by the system +/// +[Route("api/[controller]")] +public class MailTemplatesController : ESuiteControllerBase +{ + private readonly IMailTemplateManager _mailTemplateManager; + + /// + /// Constructor for MailTemplate controller + /// + /// + public MailTemplatesController(IMailTemplateManager mailTemplateManager) + { + _mailTemplateManager = mailTemplateManager; + } + + /// + /// Retrieve a list of the mail templates + /// + /// + /// + /// + [Route("types")] + [HttpGet] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetMailTemplateTypes( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _mailTemplateManager.GetMailTemplateTypes(paging, cancellationToken); + return Ok(result); + } + + /// + /// Return the details for a given mail template. It will either return the domain specific version of the template, or the master copy as used by Sun. + /// + /// + /// + /// + /// + [Route("template")] + [HttpGet] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetMailTemplate( + [FromQuery] GeneralIdRef domain, + MailType mailType, + CancellationToken cancellationToken = default! + ) + { + var result = await _mailTemplateManager.GetMailTemplate(domain, mailType, cancellationToken); + return Ok(result); + } + + /// + /// Save a mail template to the system to use by that domain. + /// + /// + /// + /// + [Route("template")] + [HttpPost] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task PostMailTemplate( + [FromBody] PostMailTemplate mailTemplate, + CancellationToken cancellationToken = default! + ) + { + await _mailTemplateManager.PostMailTemplate(mailTemplate, AuditUserDetails, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/OrganisationsController.cs b/e-suite.API/eSuite.API/Controllers/OrganisationsController.cs new file mode 100644 index 0000000..6fa6e98 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/OrganisationsController.cs @@ -0,0 +1,119 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This part of the API is responsible for allowing a user to interact with organisations. +/// +[Route("api/[controller]")] +[ApiController] +public class OrganisationsController : ESuiteControllerBase +{ + private readonly IOrganisationsManager _organisationsManager; + + /// + /// + /// + /// + public OrganisationsController(IOrganisationsManager organisationsManager) + { + _organisationsManager = organisationsManager; + } + + /// + /// Returns a list of all the organisations in the system + /// + /// This returns all the organisations in the system that are not soft deleted. + [Route("organisations")] + [HttpGet] + [AccessKey(SecurityAccess.ViewOrganisation)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetOrganisationsList([FromQuery] Paging paging, CancellationToken cancellationToken = default!) + { + var organisations = await _organisationsManager.GetOrganisationList(paging, cancellationToken); + return Ok(organisations); + } + + /// + /// Reads an organisation + /// + /// This willreturn the organisation with the specified id. + /// Either the id or the Guid of the organisation + /// + [Route("organisation")] + [HttpGet] + [AccessKey(SecurityAccess.ViewOrganisation)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetOrganisation( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var organisation = await _organisationsManager.GetOrganisation(generalIdRef, cancellationToken); + return Ok(organisation); + } + + /// + /// Create a organisation + /// + /// Contains the data required to create a organisation + /// + [Route("organisation")] + [HttpPost] + [AccessKey(SecurityAccess.AddOrganisation)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateOrganisation( + [FromBody] CreateOrganisation createOrganisationDto, + CancellationToken cancellationToken = default! + ) + { + await _organisationsManager.AddOrganisation(AuditUserDetails, createOrganisationDto, true, cancellationToken); + return Ok(); + } + + /// + /// Edit a organisation + /// + /// All the fields can be edited except the Id and Guid field + /// Contains the details of the updated organisation + /// + [Route("organisation")] + [HttpPut] + [AccessKey(SecurityAccess.EditOrganisation)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task EditOrganisation(EditOrganisation editOrganisationDto, CancellationToken cancellationToken = default!) + { + await _organisationsManager.EditOrganisation(AuditUserDetails, editOrganisationDto, true, cancellationToken); + return Ok(); + } + + /// + /// Deletes an organisation + /// + /// This will perform a soft delete action. The organisation is not actually deleted. + /// Either the id or the Guid of the organisation + /// + [Route("organisation")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteOrganisation)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteOrganisation( + GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _organisationsManager.DeleteOrganisation(AuditUserDetails, generalIdRef, true, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/ProfileController.cs b/e-suite.API/eSuite.API/Controllers/ProfileController.cs new file mode 100644 index 0000000..e922261 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/ProfileController.cs @@ -0,0 +1,63 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This part of the API is responsible for allowing a user to edit their own profile +/// +[Route("api/[controller]")] +[ApiController] +public class ProfileController : ESuiteControllerBase +{ + private readonly IUserManager _userManager; + + /// + /// + /// + /// + public ProfileController(IUserManager userManager) + { + _userManager = userManager; + } + + /// + /// Returns the general details of your profile + /// + /// This returns all the general information for your profile, e-mail, twofactor authentication key (used for setting up TFA), when your name and when the account was created. + /// + [Route("myProfile")] + [HttpGet] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetMyProfile(CancellationToken cancellationToken = default!) + { + var profile = await _userManager.GetProfile(User.Email(), cancellationToken); + return Ok(profile); + } + + /// + /// Use this method to update your own profile. + /// + /// + /// + [Route("myProfile")] + [HttpPut] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + public async Task EditMyProfile( + [FromBody] UpdatedUserProfile userProfile, + CancellationToken cancellationToken = default! + ) + { + await _userManager.UpdateProfile(AuditUserDetails, User.Email(), userProfile, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/RoleController.cs b/e-suite.API/eSuite.API/Controllers/RoleController.cs new file mode 100644 index 0000000..55455d5 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/RoleController.cs @@ -0,0 +1,275 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Allows creation and editing of security roles +/// +[Route("api/[controller]")] +[ApiController] +public class RoleController : ESuiteControllerBase +{ + private IRoleManager _roleManager; + + /// + /// Constructor for Role Controller + /// + /// + public RoleController(IRoleManager roleManager) + { + _roleManager = roleManager; + } + + /// + /// Returns a list of all the roles in the system + /// + /// This returns all the roles in the system that are not soft deleted. Use the Id or Guid column to specify a domain. + /// + /// The ID of the domain. If null, will try to access all domains + /// + /// + [Route("roles")] + [HttpGet] + [AccessKey(SecurityAccess.ViewRole)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetRoles( + [FromQuery] Paging paging, + [FromQuery] GeneralIdRef domain, + CancellationToken cancellationToken = default! + ) + { + var result = await _roleManager.GetRoles(paging, domain, cancellationToken); + return Ok(result); + } + + /// + /// Returns the details of a specific role + /// + /// This returns all the sequences in the system that are not soft deleted. + [Route("role")] + [HttpGet] + [AccessKey(SecurityAccess.ViewRole)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetRole( + [FromQuery] long? id, + [FromQuery] Guid? guid, + CancellationToken cancellationToken = default! + ) + { + var generalIdRef = new GeneralIdRef + { + Id = id, + Guid = guid + }; + + var result = await _roleManager.GetRole(generalIdRef, cancellationToken); + + return Ok(result); + } + + /// + /// Create a role + /// + /// Contains the data required to create a role + /// + [Route("role")] + [HttpPost] + [AccessKey(SecurityAccess.AddRole)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateRole( + [FromBody] CreateRole createRole, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.CreateRole(AuditUserDetails, createRole, cancellationToken); + return Ok(); + } + + /// + /// Edit a role + /// + /// All the fields can be edited except the Id and Guid field + /// Contains the details of the updated sequence + /// + [Route("role")] + [HttpPut] + [AccessKey(SecurityAccess.EditRole)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task EditRole( + [FromBody] EditRole editRole, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.EditRole(AuditUserDetails, editRole, cancellationToken); + return Ok(); + } + + /// + /// Deletes a role + /// + /// This will perform a soft delete action. + /// Either the id or the Guid of the role + /// + [Route("role")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteRole)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task DeleteRole( + GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.DeleteRole(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } + + /// + /// Returns a list of all the roles in the system + /// + /// /// This returns all the roles in the system that are not soft deleted. Use the Id or Guid column to specify a domain. + /// + /// + /// + /// + [Route("roleUsers")] + [HttpGet] + [AccessKey(SecurityAccess.ViewRoleUsers)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetRoleUsers( + [FromQuery] Paging paging, + [FromQuery] GeneralIdRef roleId, + CancellationToken cancellationToken = default! + ) + { + var result = await _roleManager.GetRoleUsers(paging, roleId, cancellationToken); + return Ok(result); + } + + /// + /// Deletes a role + /// + /// This will perform a soft delete action. + /// The ids needed to identify which role and user combination + /// + [Route("roleUsers")] + [HttpPost] + [AccessKey(SecurityAccess.AddRoleUser)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task AddRoleUser( + [FromBody] UserRoleIds userRoleIds, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.AddRoleUser(AuditUserDetails, userRoleIds, cancellationToken); + return Ok(); + } + + /// + /// Deletes a role + /// + /// This will perform a soft delete action. + /// The ids needed to identify which role and user combination + /// + [Route("roleUsers")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteRoleUser)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task DeleteRoleUser( + [FromBody] UserRoleIds userRoleIds, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.DeleteRoleUser(AuditUserDetails, userRoleIds, cancellationToken); + return Ok(); + } + + /// + /// Returns a list of all the access rights available in the system. + /// + /// This is the master list of access rights that may be assigned to roles. + /// + /// + /// + [Route("accessList")] + [HttpGet] + [AccessKey(SecurityAccess.ViewAccessList)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetAccessList( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _roleManager.GetAccessList(paging, cancellationToken); + return Ok(result); + } + + /// + /// Returns a list of all the access rights assigned to roles. + /// + /// + /// + /// + [Route("roleAccess")] + [HttpGet] + [AccessKey(SecurityAccess.ViewRoleAccess)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetRoleAccess( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _roleManager.GetRoleAccess(paging, cancellationToken); + return Ok(result); + } + + /// + /// + /// + /// + /// + /// + [Route("roleAccess")] + [HttpPost] + [AccessKey(SecurityAccess.EditRoleAccess)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task PostRoleAccess( + [FromBody] AddRoleSecurityAccess accessToAdd, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.AddRoleSecurityAccess(AuditUserDetails, accessToAdd, cancellationToken); + return Ok(); + } + + /// + /// + /// + /// + /// + /// + [Route("roleAccess")] + [HttpDelete] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task DeleteRoleAccess( + [FromBody] DeleteRoleSecurityAccess accessToRemove, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.DeleteRoleSecurityAccess(AuditUserDetails, accessToRemove, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/SequencesController.cs b/e-suite.API/eSuite.API/Controllers/SequencesController.cs new file mode 100644 index 0000000..fda0211 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/SequencesController.cs @@ -0,0 +1,154 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.Models; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// This part of the API is responsible for allowing a user to interact with sequences. +/// +[Route("api/[controller]")] +[ApiController] +public class SequencesController : ESuiteControllerBase +{ + private readonly ISequenceManager _sequenceManager; + + /// + /// + /// + /// + public SequencesController(ISequenceManager sequenceManager) + { + _sequenceManager = sequenceManager; + } + + /// + /// Returns a list of all the sequences in the system + /// + /// This returns all the sequences in the system that are not soft deleted. + [Route("sequences")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSequence)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetSequences( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _sequenceManager.GetSequences(paging, cancellationToken); + return Ok(result); + } + + /// + /// Returns the details of a specific sequence + /// + /// This returns all the sequences in the system that are not soft deleted. + [Route("sequence")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSequence)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetSequence( + [FromQuery] long? id, + [FromQuery] Guid? guid, + CancellationToken cancellationToken = default! + ) + { + var generalIdRef = new GeneralIdRef + { + Id = id, + Guid = guid + }; + + var result = await _sequenceManager.GetSequence(generalIdRef, cancellationToken); + + return Ok(result); + } + + /// + /// Create a sequence + /// + /// Contains the data required to create a sequence + /// + [Route("sequence")] + [HttpPost] + [AccessKey(SecurityAccess.AddSequence)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateSequence( + [FromBody] NewSequence createSequence, + CancellationToken cancellationToken = default! + ) + { + await _sequenceManager.CreateSequence(AuditUserDetails, createSequence, cancellationToken); + return Ok(); + } + + /// + /// Edit a sequence + /// + /// All the fields can be edited except the Id and Guid field + /// Contains the details of the updated sequence + /// + [Route("sequence")] + [HttpPut] + [AccessKey(SecurityAccess.EditSequence)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task EditSequence( + [FromBody] Sequence editSequence, + CancellationToken cancellationToken = default! + ) + { + await _sequenceManager.EditSequence(AuditUserDetails, editSequence, cancellationToken); + return Ok(); + } + + /// + /// Deletes a sequence + /// + /// This will perform a soft delete action. The sequence is not actually deleted. + /// Either the id or the Guid of the sequence + /// + [Route("sequence")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteSequence)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task DeleteSequence( + GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _sequenceManager.DeleteSequence(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } + + /// + /// Issues one or more sequence numbers + /// + /// This will issue a sequence number acording to the pattern of the sequence. + /// details of the sequence requested + /// + [Route("nextValue")] + [HttpPost] + [AccessKey(SecurityAccess.Everyone)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task NextValue( + [FromBody] SequenceIssueRequest sequenceIssueRequest, + CancellationToken cancellationToken = default! + ) + { + var values = await _sequenceManager.NextValue(AuditUserDetails, sequenceIssueRequest.GeneralIdRef, + sequenceIssueRequest.Count, cancellationToken); + return Ok(values); + } +} + diff --git a/e-suite.API/eSuite.API/Controllers/SiteController.cs b/e-suite.API/eSuite.API/Controllers/SiteController.cs new file mode 100644 index 0000000..48ca12d --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/SiteController.cs @@ -0,0 +1,123 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// forms manager is responsible for managing custom forms within e-suite. +/// +[Route("api/[controller]")] +public class SiteController : ESuiteControllerBase +{ + private readonly ISiteManager _siteManager; + + /// + /// Constructor for the SiteController + /// + /// + public SiteController(ISiteManager siteManager) + { + _siteManager = siteManager; + } + + /// + /// Gets all sites + /// + /// Collection of all FormTemplates + [Route("sites")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSite)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetSites( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _siteManager.GetSites(paging, cancellationToken); + return Ok(result); + } + + /// + /// Get site by supplying GeneralIdRef + /// + /// + /// + /// Returns the FormTemplate with the corresponding Id + [Route("site")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSite)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetSite( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var site = await _siteManager.GetSite(generalIdRef, cancellationToken); + return Ok(site); + } + + /// + /// Create site + /// + /// + /// + [Route("site")] + [HttpPost] + [AccessKey(SecurityAccess.AddSite)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task CreateSite([FromBody] CreateSite createSite, CancellationToken cancellationToken = default!) + { + await _siteManager.CreateSite(AuditUserDetails, createSite, true, cancellationToken); + return Ok(); + } + + /// + /// Edit site + /// + /// + /// + [Route("site")] + [HttpPut] + [AccessKey(SecurityAccess.EditSite)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task EditSite( + [FromBody] EditSite editSite, + CancellationToken cancellationToken = default! + ) + { + await _siteManager.EditSite(AuditUserDetails, editSite, true, cancellationToken); + return Ok(); + } + + /// + /// Delete a site + /// + /// + /// + [Route("site")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteSite)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteSite( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _siteManager.DeleteSite(AuditUserDetails, generalIdRef, true, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/SpecificationController.cs b/e-suite.API/eSuite.API/Controllers/SpecificationController.cs new file mode 100644 index 0000000..a3e99f7 --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/SpecificationController.cs @@ -0,0 +1,143 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// forms manager is responsible for managing custom forms within e-suite. +/// +[Route("api/[controller]")] +public class SpecificationController : ESuiteControllerBase +{ + private readonly ISpecificationManager _specificationManager; + + /// + /// Constructor for Specification Controller + /// + /// + public SpecificationController(ISpecificationManager specificationManager) + { + _specificationManager = specificationManager; + } + + /// + /// Gets all specifications + /// + /// Collection of all FormTemplates + [Route("specifications")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSpecification)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetSpecifications( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _specificationManager.GetSpecifications(paging, cancellationToken); + return Ok(result); + } + + /// + /// Get specification by supplying GeneralIdRef + /// + /// + /// + /// Returns the FormTemplate with the corresponding Id + [Route("specification")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSpecification)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetSpecification( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var site = await _specificationManager.GetSpecification(generalIdRef, cancellationToken); + return Ok(site); + } + + /// + /// Gets the form template for a given print specification + /// + /// IdRef of specification glossary which has the form template saved as a custom value + /// + /// + [Route("getTemplateForPrintSpec")] + [HttpGet] + [AccessKey(SecurityAccess.ViewTemplateForPrintSpec)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetTemplateForPrintSpec( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var site = await _specificationManager.GetTemplateForPrintSpec(generalIdRef, cancellationToken); + return Ok(site); + } + + /// + /// Create a new Specification. Linking it to the associated form instance + /// + /// + /// + /// + [Route("specification")] + [HttpPost] + [AccessKey(SecurityAccess.AddSpecification)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task CreateSpecification([FromBody] CreateSpecification create, CancellationToken cancellationToken = default!) + { + await _specificationManager.CreateSpecification(AuditUserDetails, create, true, cancellationToken); + return Ok(); + } + + /// + /// Edit a specification + /// + /// + /// + /// + [Route("specification")] + [HttpPut] + [AccessKey(SecurityAccess.EditSpecification)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task EditSpecification([FromBody] EditSpecification edit, CancellationToken cancellationToken = default!) + { + await _specificationManager.EditSpecification(AuditUserDetails, edit, true, cancellationToken); + return Ok(); + } + + /// + /// Delete a specification + /// + /// + /// + [Route("specification")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteSpecification)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteSpecification( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _specificationManager.DeleteSpecification(AuditUserDetails, generalIdRef, true, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/SsoManagerController.cs b/e-suite.API/eSuite.API/Controllers/SsoManagerController.cs new file mode 100644 index 0000000..ab0bb4e --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/SsoManagerController.cs @@ -0,0 +1,124 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Utilities.Pagination; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Controllers; + +/// +/// Sso manager is responsible for configuring Single Sign On Providers +/// +[Route("api/[controller]")] +public class SsoManagerController : ESuiteControllerBase +{ + private readonly ISsoManager _ssoManager; + + /// + /// Constructor for the SsoManager + /// + /// + public SsoManagerController(ISsoManager ssoManager) + { + _ssoManager = ssoManager; + } + + /// + /// Gets all SsoProviders + /// + /// Collection of all SsoProviders + [Route("ssoProviders")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSsoProviders)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetProviders( + [FromQuery] Paging paging, + CancellationToken cancellationToken = default! + ) + { + var result = await _ssoManager.GetSsoProvidersAsync(paging, cancellationToken); + return Ok(result); + } + + /// + /// Get SsoProvider details + /// + /// + /// + /// + [Route("ssoProvider")] + [HttpGet] + [AccessKey(SecurityAccess.ViewSsoProviders)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task GetProvider( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var result = await _ssoManager.GetSsoProviderAsync(generalIdRef, cancellationToken); + return Ok(result); + } + + /// + /// Add new Sso Provider + /// + /// + /// + /// + [Route("ssoProvider")] + [HttpPost] + [AccessKey(SecurityAccess.AddSsoProvider)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + public async Task AddProvider( + [FromBody] CreateSsoProvider ssoProvider, + CancellationToken cancellationToken = default! + ) + { + await _ssoManager.AddSsoProviderAsync(AuditUserDetails, ssoProvider, cancellationToken); + return Ok(); + } + + /// + /// Edit SsoProvider + /// + /// + /// + /// + [Route("ssoProvider")] + [HttpPut] + [AccessKey(SecurityAccess.EditSsoProvider)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task EditSsoProvider( + [FromBody] EditSsoProvider editedSsoProvider, + CancellationToken cancellationToken = default! + ) + { + await _ssoManager.EditSsoProviderAsync(AuditUserDetails, editedSsoProvider, cancellationToken); + return Ok(); + } + + /// + /// Delete SsoProvider + /// + /// + /// + /// + [Route("ssoProvider")] + [HttpDelete] + [AccessKey(SecurityAccess.DeleteSsoProvider)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + public async Task DeleteSsoProvider( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _ssoManager.RemoveSsoProviderAsync(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Controllers/UserController.cs b/e-suite.API/eSuite.API/Controllers/UserController.cs new file mode 100644 index 0000000..6c2dadb --- /dev/null +++ b/e-suite.API/eSuite.API/Controllers/UserController.cs @@ -0,0 +1,194 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Utilities.Pagination; +using eSuite.API.Models; +using eSuite.API.security; +using eSuite.API.Utilities; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using Microsoft.AspNetCore.Mvc; +using IRoleManager = e_suite.API.Common.IRoleManager; + +namespace eSuite.API.Controllers; + +/// +/// User manage is responsible for managing users within e-suite. +/// +[Route("api/[controller]")] +[ApiController] +public class UserController : ESuiteControllerBase +{ + private readonly IUserManager _userManager; + private readonly IRoleManager _roleManager; + + /// + /// Constructor for user controller + /// + /// + /// + public UserController(IUserManager userManager, IRoleManager roleManager) + { + _userManager = userManager; + _roleManager = roleManager; + } + + /// + /// Get a list of the users + /// + /// + /// + /// + [Route("users")] + [AccessKey(SecurityAccess.ViewUser)] + [HttpGet] + public async Task GetUsers([FromQuery] Paging paging, CancellationToken cancellationToken = default!) + { + var result = await _userManager.GetUsersAsync(paging, cancellationToken); + return Ok(result); + } + + /// + /// Get the details of a specific user + /// + /// + /// + /// + [Route("user")] + [HttpGet] + [AccessKey(SecurityAccess.ViewUser)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetUser( + [FromQuery] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + var user = await _userManager.GetUserAsync(generalIdRef, cancellationToken); + return Ok(user); + } + + /// + /// Edit a user + /// + /// + /// + /// + [Route("user")] + [HttpPut] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [AccessKey(SecurityAccess.EditUser)] + public async Task EditUser(EditUser user, CancellationToken cancellationToken = default!) + { + await _userManager.EditUser(AuditUserDetails, user, cancellationToken); + return Ok(); + } + + /// + /// Create a new e-suite user + /// + /// Create a new user for e-suite. The minimum information needed is the email address, which forms the account user name. Once created the user will get an e-mail asking them to confirm the account. + /// Contains the details that need to be supplied to create the user. + /// + /// + [Route("user")] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [AccessKey(SecurityAccess.AddUser)] + public async Task CreateUser( + [FromBody] UserRegistration userRegistration, + CancellationToken cancellationToken = default! + ) + { + await _roleManager.CheckHasDomainAccess(AuditUserDetails.UserId, userRegistration.DomainId, + SecurityAccess.AddUser, cancellationToken); + + await _userManager.CreateUser(AuditUserDetails, userRegistration, cancellationToken); + return Ok(); + } + + /// + /// Use this to deactivate a user from being able to access e-suite. This will stop them from being able to log in. + /// + /// + /// + [Route("userByEmail")] + [HttpDelete] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [AccessKey(SecurityAccess.DeleteUser)] + public async Task DeactivateUser( + [FromBody] EmailAddress email, + CancellationToken cancellationToken = default! + ) + { + await _userManager.DeactivateUser(AuditUserDetails, email.Email, cancellationToken); + return Ok(); + } + + /// + /// Use this to deactivate a user from being able to access e-suite. This will stop them from being able to log in. + /// + /// + /// + [Route("user")] + [HttpDelete] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [AccessKey(SecurityAccess.DeleteUser)] + public async Task DeactivateUser( + [FromBody] GeneralIdRef generalIdRef, + CancellationToken cancellationToken = default! + ) + { + await _userManager.DeactivateUser(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } + + /// + /// User this to have the API resend the account confirmation e-mail to a given user. + /// + /// + /// + /// + /// + [Route("resendConfirmEmail")] + [HttpPost] + [AccessKey(SecurityAccess.ResendConfirmMail)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + public async Task ResendConfirmEmail([FromBody] GeneralIdRef generalIdRef, CancellationToken cancellationToken = default!) + { + ArgumentNullException.ThrowIfNull(generalIdRef); + + await _userManager.ResendConfirmEmail(AuditUserDetails, generalIdRef, cancellationToken); + return Ok(); + } + + /// + /// Intended for internal use, this allows you to retrieve the current email action url for a given user + /// + /// + /// + /// + /// + [Route("currentEmailUserActionUrl")] + [HttpGet] + [AccessKey(SecurityAccess.GetCurrentEmailActionUrl)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))] + public async Task CurrentEmailUserActionUrl( + string emailAddress, + EmailUserActionType emailUserActionType, CancellationToken cancellationToken = default + ) + { + var url = await _userManager.GetCurrentEmailActionUrl(emailAddress, emailUserActionType, cancellationToken); + return Ok(url); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/DependencyInjection/CoreRegistrationModule.cs b/e-suite.API/eSuite.API/DependencyInjection/CoreRegistrationModule.cs new file mode 100644 index 0000000..c15366a --- /dev/null +++ b/e-suite.API/eSuite.API/DependencyInjection/CoreRegistrationModule.cs @@ -0,0 +1,45 @@ +using Autofac; +using eSuite.API.SingleSignOn; +using eSuite.Core.Clock; + +namespace eSuite.API.DependencyInjection; + +/// +/// Used as the primary location for IOC type registration for e-suite. +/// +internal class CoreRegistrationModule : Module +{ + /// + /// Use the builder to register all the types and interfaces that the API requires to operate properly. + /// + /// + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + e_suite.Service.Mail.IocRegistration.RegisterTypes(builder); + e_suite.Service.Sentinel.IocRegistration.RegisterTypes(builder); + + e_suite.Modules.CustomFieldsManager.IocRegistration.RegisterTypes(builder); + e_suite.Service.CustomFieldValidation.IocRegistration.RegisterTypes(builder); + e_suite.Modules.FormsManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.GlossariesManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.OrganisationsManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.SequenceManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.UserManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.AuditLog.IocRegistration.RegisterTypes(builder); + e_suite.Modules.DomainManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.MailTemplatesManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.RoleManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.SiteManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.SpecificationManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.BlockedIPsManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.ExceptionLogManager.IocRegistration.RegisterTypes(builder); + e_suite.Modules.SSOManager.IocRegistration.RegisterTypes(builder); + + e_suite.Messaging.Common.DependencyInjection.CoreRegistrationModule.Load(builder); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Dockerfile b/e-suite.API/eSuite.API/Dockerfile new file mode 100644 index 0000000..7e6822d --- /dev/null +++ b/e-suite.API/eSuite.API/Dockerfile @@ -0,0 +1,24 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src +COPY ["nuget.config", "."] +COPY ["TestApp1/TestApp1.csproj", "TestApp1/"] +RUN dotnet restore "TestApp1/TestApp1.csproj" +COPY . . +WORKDIR "/src/TestApp1" +RUN dotnet build "TestApp1.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "TestApp1.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +ENV ASPNETCORE_HTTP_PORTS=80 +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "eSuite.API.dll"] \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Dockerfile.Azure b/e-suite.API/eSuite.API/Dockerfile.Azure new file mode 100644 index 0000000..eaac06a --- /dev/null +++ b/e-suite.API/eSuite.API/Dockerfile.Azure @@ -0,0 +1,10 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 as base +ENV DOTNET_ENVIRONMENT=Development +ENV ASPNETCORE_HTTP_PORTS=80 +WORKDIR /app +COPY . . +EXPOSE 8080 +EXPOSE 8081 +ENTRYPOINT ["dotnet", "eSuite.API.dll"] \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Extensions/StringExtensions.cs b/e-suite.API/eSuite.API/Extensions/StringExtensions.cs new file mode 100644 index 0000000..9be790a --- /dev/null +++ b/e-suite.API/eSuite.API/Extensions/StringExtensions.cs @@ -0,0 +1,14 @@ +namespace eSuite.API.Extensions; + +internal static class StringExtensions +{ + public static long? ToLong(this string? value) + { + if (value == null) + { + return null; + } + + return long.TryParse(value, out var result) ? result : null; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Extensions/UserProfileExtensions.cs b/e-suite.API/eSuite.API/Extensions/UserProfileExtensions.cs new file mode 100644 index 0000000..d47c8a9 --- /dev/null +++ b/e-suite.API/eSuite.API/Extensions/UserProfileExtensions.cs @@ -0,0 +1,35 @@ +using e_suite.API.Common.models; + +namespace eSuite.API.Extensions; + +internal static class UserProfileExtensions +{ + internal static Models.UserProfile ToUserProfile(this UserProfile userProfile) + { + return new Models.UserProfile + { + Email = userProfile.Email, + FirstName = userProfile.FirstName, + LastName = userProfile.LastName, + MiddleNames = userProfile.MiddleNames, + UsingTwoFactorAuthentication = userProfile.UsingTwoFactorAuthentication, + TwoFactorAuthenticationSettings = userProfile.TwoFactorAuthenticationSettings, + DomainSsoProviderId = userProfile.DomainSsoProviderId, + SsoProviderId = userProfile.SsoProviderId ?? -1, + SsoSubject = userProfile.SsoSubject, + SsoProviders = userProfile.SsoProviders + }; + } + + internal static Models.ConfirmEmailAccount ToConfirmEmailAccount(this UserProfile userProfile) + { + return new Models.ConfirmEmailAccount + { + UsingTwoFactorAuthentication = userProfile.UsingTwoFactorAuthentication, + TwoFactorAuthenticationSettings = userProfile.TwoFactorAuthenticationSettings, + DomainSsoProviderId = userProfile.DomainSsoProviderId, + SsoProviderId = userProfile.SsoProviderId ?? -1, + SsoProviders = userProfile.SsoProviders, + }; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/GlobalSuppressions.cs b/e-suite.API/eSuite.API/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.API/eSuite.API/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.API/eSuite.API/HealthChecks/ISocketFacade.cs b/e-suite.API/eSuite.API/HealthChecks/ISocketFacade.cs new file mode 100644 index 0000000..80de1bf --- /dev/null +++ b/e-suite.API/eSuite.API/HealthChecks/ISocketFacade.cs @@ -0,0 +1,40 @@ +using System.Net; +using System.Net.Sockets; + +namespace eSuite.API.HealthChecks; + +/// +/// Interface that allows a socket to be created and mocked +/// +public interface ISocketFacade : IDisposable +{ + /// + /// Calls the socket connect method. + /// + /// + void Connect(IPEndPoint endPoint); + + /// + /// Calls the socket Send method. + /// + /// + /// + /// + /// + void Send(byte[] dataArray, int offset, int size, SocketFlags socketFlags); + + /// + /// Number of bytes available for reading + /// + int Available { get; } + + /// + /// Receive data from the socket using the parameters provided + /// + /// + /// + /// + /// + /// + int Receive(byte[] responseArray, int offset, int size, SocketFlags socketFlags); +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/HealthChecks/ISocketFactory.cs b/e-suite.API/eSuite.API/HealthChecks/ISocketFactory.cs new file mode 100644 index 0000000..3552bfc --- /dev/null +++ b/e-suite.API/eSuite.API/HealthChecks/ISocketFactory.cs @@ -0,0 +1,18 @@ +using System.Net.Sockets; + +namespace eSuite.API.HealthChecks; + +/// +/// Interface for for a factory class that creates Sockets +/// +public interface ISocketFactory +{ + /// + /// Creates a socket using the parameters provided. + /// + /// + /// + /// + /// + ISocketFacade CreateSocket(AddressFamily endPointAddressFamily, SocketType stream, ProtocolType tcp); +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/HealthChecks/SmtpHealthCheck.cs b/e-suite.API/eSuite.API/HealthChecks/SmtpHealthCheck.cs new file mode 100644 index 0000000..1e43c58 --- /dev/null +++ b/e-suite.API/eSuite.API/HealthChecks/SmtpHealthCheck.cs @@ -0,0 +1,89 @@ +using System.Net; +using System.Net.Sockets; +using System.Text; +using e_suite.Service.Mail.Helper; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace eSuite.API.HealthChecks; + +/// +/// Health check used to perform a basic check to see that the smtp server is available. +/// +public class SmtpHealthCheck +{ + /// + /// Returns Health check result for if the smtp server is up and available to connect too. + /// + /// + /// + /// + public static HealthCheckResult Healthy(IConfiguration configuration, ISocketFactory socketFactory) + { + //failure to be able to send an email should result in degraded. + + var host = configuration.GetConfigValue("MAIL_SERVER", "Smtp:Server", "defaultmailserver"); + var port = configuration.GetConfigValue("MAIL_PORT", "Smtp:Port", 25); + //var fromAddress = configuration.GetConfigValue("MAIL_ADDRESS", "Smtp:FromAddress", "defaultfromaddress"); + //var fromDisplayName = configuration.GetConfigValue("MAIL_NAME", "Smtp:FromDisplayName", "MailService"); + //var username = configuration.GetConfigValue("MAIL_USERNAME", "Smtp:Username", string.Empty); + //var password = configuration.GetConfigValue("MAIL_PASSWORD", "Smtp:Password", string.Empty); + //var enableSsl = configuration.GetConfigValue("MAIL_ENABLE_SSL", "Smtp:EnableSSL", false); + //client.Timeout = _configuration.GetConfigValue("MAIL_TIMEOUT", "Smtp:timeout", 30000); + var isServerOk = TestConnection(host!, port, socketFactory); + if (!isServerOk) + return HealthCheckResult.Unhealthy("Unable to connect to SMTP Server"); + + return HealthCheckResult.Healthy(); + } + + /// + /// Performs the test to connect to the smtp server to see that the server is functional. + /// + /// + /// + /// + /// + public static bool TestConnection(string smtpServerAddress, int port, ISocketFactory socketFactory) + { + var hostEntry = Dns.GetHostEntry(smtpServerAddress); + var endPoint = new IPEndPoint(hostEntry.AddressList[0], port); + using (var tcpSocket = socketFactory.CreateSocket( endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) + { + //try to connect and test the rsponse for code 220 = success + tcpSocket.Connect(endPoint); + if (!CheckResponse(tcpSocket, 220)) + { + return false; + } + + // send HELO and test the response for code 250 = proper response + SendData(tcpSocket, $"HELO {Dns.GetHostName()}\r\n"); + if (!CheckResponse(tcpSocket, 250)) + { + return false; + } + + // if we got here it's that we can connect to the smtp server + return true; + } + } + + private static void SendData(ISocketFacade socket, string data) + { + var dataArray = Encoding.ASCII.GetBytes(data); + socket.Send(dataArray, 0, dataArray.Length, SocketFlags.None); + } + + private static bool CheckResponse(ISocketFacade socket, int expectedCode) + { + while (socket.Available == 0) + { + Thread.Sleep(100); + } + var responseArray = new byte[1024]; + socket.Receive(responseArray, 0, socket.Available, SocketFlags.None); + var responseData = Encoding.ASCII.GetString(responseArray); + var responseCode = Convert.ToInt32(responseData.Substring(0, 3)); + return responseCode == expectedCode; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/HealthChecks/SocketFacade.cs b/e-suite.API/eSuite.API/HealthChecks/SocketFacade.cs new file mode 100644 index 0000000..0b66313 --- /dev/null +++ b/e-suite.API/eSuite.API/HealthChecks/SocketFacade.cs @@ -0,0 +1,77 @@ +using System.Net; +using System.Net.Sockets; + +namespace eSuite.API.HealthChecks; + +/// +/// Class to provide and interface facade for the Socket class +/// +public class SocketFacade : ISocketFacade +{ + private Socket _socket; + + /// + /// Creates a new Socket using the parameters provided. + /// + /// + /// + /// + public SocketFacade(AddressFamily endPointAddressFamily, SocketType stream, ProtocolType tcp) + { + _socket = new Socket(endPointAddressFamily, stream, tcp); + } + + + /// + /// Disposes of the underlying socket. + /// + public void Dispose() + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (_socket == null) + return; + + GC.SuppressFinalize(this); + _socket.Dispose(); + _socket = null!; + } + + /// + /// Connect to the socket + /// + /// + public void Connect(IPEndPoint endPoint) + { + _socket.Connect(endPoint); + } + + /// + /// Sends data to the socket + /// + /// + /// + /// + /// + public void Send(byte[] dataArray, int offset, int size, SocketFlags socketFlags) + { + _socket.Send(dataArray, offset, size, socketFlags); + } + + /// + /// Receives data from the socket + /// + /// + /// + /// + /// + /// + public int Receive(byte[] responseArray, int offset, int size, SocketFlags socketFlags) + { + return _socket.Receive(responseArray, offset, size, socketFlags); + } + + /// + /// Number of bytes available for reading. + /// + public int Available => _socket.Available; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/HealthChecks/SocketFactory.cs b/e-suite.API/eSuite.API/HealthChecks/SocketFactory.cs new file mode 100644 index 0000000..7a63c7d --- /dev/null +++ b/e-suite.API/eSuite.API/HealthChecks/SocketFactory.cs @@ -0,0 +1,21 @@ +using System.Net.Sockets; + +namespace eSuite.API.HealthChecks; + +/// +/// Factory class used to create sockets +/// +public class SocketFactory : ISocketFactory +{ + /// + /// Create a new socket using the parameters provided. + /// + /// + /// + /// + /// + public ISocketFacade CreateSocket(AddressFamily endPointAddressFamily, SocketType stream, ProtocolType tcp) + { + return new SocketFacade(endPointAddressFamily, stream, tcp); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Middleware/AuthenticationExtension.cs b/e-suite.API/eSuite.API/Middleware/AuthenticationExtension.cs new file mode 100644 index 0000000..f21f09b --- /dev/null +++ b/e-suite.API/eSuite.API/Middleware/AuthenticationExtension.cs @@ -0,0 +1,56 @@ +using System.Text; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; + +namespace eSuite.API.Middleware; + +/// +/// Methods used to extend WebAPI authentication to use the Bearer token. +/// +internal static class AuthenticationExtension +{ + public const string SessionCookieName = "eSuiteSession"; + + /// + /// Adds support for JWT Tokens passed as Bearer to the application. + /// + /// + public static void AddTokenAuthentication(this WebApplicationBuilder builder) + { + builder.Services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.SaveToken = true; + options.RequireHttpsMetadata = true; + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateIssuerSigningKey = true, + ValidateLifetime = true, + ValidAudience = builder.Configuration["JwtConfig:audience"], + ValidIssuer = builder.Configuration["JwtConfig:issuer"], + IssuerSigningKey = + new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtConfig:secret"]!)), + ClockSkew = TimeSpan.FromSeconds(5) + }; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + if (context.Request.Cookies.ContainsKey(SessionCookieName)) + { + context.Token = context.Request.Cookies[SessionCookieName]; + } + + return Task.CompletedTask; + } + }; + }); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Middleware/ExceptionCapture.cs b/e-suite.API/eSuite.API/Middleware/ExceptionCapture.cs new file mode 100644 index 0000000..95b03a7 --- /dev/null +++ b/e-suite.API/eSuite.API/Middleware/ExceptionCapture.cs @@ -0,0 +1,171 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Extensions.Exceptions; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; + +namespace eSuite.API.Middleware; + +/// +/// Exception capture middleware +/// +public class ExceptionCapture +{ + private readonly RequestDelegate _next; + private readonly IExceptionLogManager _exceptionLogManager; + + /// + /// Default constructor + /// + /// + /// + public ExceptionCapture(RequestDelegate next, IExceptionLogManager exceptionLogManager) + { + _next = next; + _exceptionLogManager = exceptionLogManager; + } + + /// + /// Called to wrap the controller method with general graceful error handling + /// + /// + /// + public async Task InvokeAsync(HttpContext context) + { + try + { + await _next.Invoke(context); + } + catch (GuidMismatchException ex) + { + await BadRequestResponse(context, ex); + } + catch (NotFoundException ex) + { + await NotFoundResponse(context, ex); + } + catch (ExistsException ex) + { + await BadRequestResponse(context, ex); + } + catch (InvalidOperationException ex) + { + await BadRequestResponse(context, ex); + } + catch( ValidationException ex) + { + await BadRequestResponse(context, ex); + } + catch (ArgumentException ex) + { + await BadRequestResponse(context, ex); + } + catch (InvalidReferenceObjectId ex) + { + await BadRequestResponse(context, ex); + } + catch (TokenInvalidException ex) + { + await BadRequestResponse(context, ex); + } + catch (InvalidEmailException ex) + { + await BadRequestResponse(context, ex); + } + catch (MinimumRangeException ex) + { + await BadRequestResponse(context, ex); + } + catch (MaximumRangeException ex) + { + await BadRequestResponse(context, ex); + } + catch (OperationCanceledException ex) + { + await BadRequestResponse(context, ex, "Request cancelled"); + } + catch (Exception ex) + { + var supportingData = new + { + User = context.User.Identity != null ? context.User.Identity.Name : string.Empty, + context.Request.Query, + context.Request.Method, + context.Request.Path, + context.Request.Headers, + context.Request.Cookies, + context.Request.QueryString, + context.Items + }.ToJson(); + + var exceptionId = await _exceptionLogManager.LogException(ex, "e-suite API", supportingData, CancellationToken.None); + await InternalServerErrorResponse(context, ex, exceptionId); + } + } + + private static async Task BadRequestResponse(HttpContext context, Exception ex, string title = "Bad request") + { + var problemDetails = new ProblemDetails + { + Title = title, + Detail = ex.Message + }; + + context.Response.StatusCode = StatusCodes.Status400BadRequest; + context.Response.ContentType = "application/json"; + + await context.Response.WriteAsync(problemDetails.ToJson()); + } + + private static async Task NotFoundResponse(HttpContext context, Exception ex, string title = "Not found") + { + var problemDetails = new ProblemDetails + { + Title = title, + Detail = ex.Message + }; + + context.Response.StatusCode = StatusCodes.Status404NotFound; + context.Response.ContentType = "application/json"; + + await context.Response.WriteAsync(problemDetails.ToJson()); + } + + private static async Task InternalServerErrorResponse(HttpContext context, Exception ex, long exceptionId, string title = "Internal Server Error") + { + var problemDetails = new ProblemDetails + { + Title = title, + Detail = ex.Message, + Instance = exceptionId.ToString() + }; + + context.Response.StatusCode = StatusCodes.Status500InternalServerError; + context.Response.ContentType = "application/json"; + + await context.Response.WriteAsync(problemDetails.ToJson()); + } +} + +/// +/// +/// +public static class ObjectExtensions +{ + /// + /// Serialize the current object to Json + /// + /// + /// + public static string ToJson(this object value) + { + var options = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + NullValueHandling = NullValueHandling.Include + }; + return JsonConvert.SerializeObject(value, options); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Middleware/OptionsMiddleware.cs b/e-suite.API/eSuite.API/Middleware/OptionsMiddleware.cs new file mode 100644 index 0000000..3d974bf --- /dev/null +++ b/e-suite.API/eSuite.API/Middleware/OptionsMiddleware.cs @@ -0,0 +1,41 @@ +namespace eSuite.API.Middleware; + +/// +/// Adds support for the cors options pre-flight check +/// +public class OptionsMiddleware +{ + private readonly RequestDelegate _next; + + /// + /// Default constructor + /// + /// + public OptionsMiddleware(RequestDelegate next) + { + _next = next; + } + + /// + /// Called by asp.net. + /// + /// + /// + public Task Invoke(HttpContext context) + { + if (context.Request.Method == "OPTIONS") + { + context.Response.Headers.AccessControlAllowOrigin = (string)context.Request.Headers.Origin!; + //context.Response.Headers.Add("Access-Control-Allow-Origin", + // new[] { (string)context.Request.Headers["Origin"] }); + //context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); + context.Response.Headers.AccessControlAllowHeaders = new[] {"Origin, X-Requested-With, Content-Type, Accept, Authorization"}; + context.Response.Headers.AccessControlAllowMethods = new[] {"GET, POST, PUT, DELETE, OPTIONS"}; + context.Response.Headers.AccessControlAllowCredentials = new[] {"true"}; + context.Response.StatusCode = 200; + return context.Response.WriteAsync("OK"); + } + + return _next.Invoke(context); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Middleware/SecurityAccessMiddleWare.cs b/e-suite.API/eSuite.API/Middleware/SecurityAccessMiddleWare.cs new file mode 100644 index 0000000..4c19669 --- /dev/null +++ b/e-suite.API/eSuite.API/Middleware/SecurityAccessMiddleWare.cs @@ -0,0 +1,83 @@ +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using eSuite.API.security; +using eSuite.API.Utilities; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; +using Autofac; +using Autofac.Core.Lifetime; + +namespace eSuite.API.Middleware; + +internal class SecurityAccessMiddleWare +{ + private readonly RequestDelegate _next; + private readonly ILifetimeScope _lifetimeScope; + + public SecurityAccessMiddleWare(RequestDelegate next, ILifetimeScope lifetimeScope) + { + _next = next; + _lifetimeScope = lifetimeScope; + } + + public async Task InvokeAsync(HttpContext context) + { + var endpoint = context.GetEndpoint() ?? throw new NotFoundException("Endpoint not found"); + + if (endpoint is RouteEndpoint routeEndpoint) + { + if (routeEndpoint.RoutePattern.RawText != null) + { + var allowAnonymousAttribute = endpoint?.Metadata.OfType().FirstOrDefault(); + + var routePatternLower = routeEndpoint.RoutePattern.RawText.ToLower().TrimStart('/'); + if (allowAnonymousAttribute != null || !(routePatternLower.StartsWith("api") || routePatternLower.StartsWith("account"))) + { + await _next.Invoke(context); + return; + } + } + } + + var accessKeyAttribute = endpoint?.Metadata.OfType().FirstOrDefault() ?? throw new NotImplementedException("Unable to find AccessKeyAttribute for Endpoint"); + + var userId = GetUserIdFromContextUser(context.User).GetValueOrDefault(); + + var accessKey = accessKeyAttribute.SecurityAccess; + + await using var requestLifetimeScope = _lifetimeScope.BeginLifetimeScope(); + var roleManager = requestLifetimeScope.Resolve(); + + if (await roleManager.HasAnyAccess(userId, accessKey)) + { + await _next.Invoke(context); + return; + } + + var problemDetails = new ProblemDetails + { + Title = "Unauthorised", + Detail = "User does not have permission to call this method" + }; + + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.ContentType = "application/json"; + + await context.Response.WriteAsync(problemDetails.ToJson()); + } + private static long? GetUserIdFromContextUser(ClaimsPrincipal user) + { + long? userId; + try + { + userId = user.Id(); + } + catch + { + userId = null; + } + + return userId; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Models/BlockedIPAddress.cs b/e-suite.API/eSuite.API/Models/BlockedIPAddress.cs new file mode 100644 index 0000000..99fb1d4 --- /dev/null +++ b/e-suite.API/eSuite.API/Models/BlockedIPAddress.cs @@ -0,0 +1,12 @@ +namespace eSuite.API.Models; + +/// +/// Data transfer class for unblocking the IP Address +/// +public class BlockedIPAddress +{ + /// + /// IPAddress that will be unblocked + /// + public string IpAddress { get; set; } = string.Empty; +} diff --git a/e-suite.API/eSuite.API/Models/ConfirmEmailAccount.cs b/e-suite.API/eSuite.API/Models/ConfirmEmailAccount.cs new file mode 100644 index 0000000..e5426f7 --- /dev/null +++ b/e-suite.API/eSuite.API/Models/ConfirmEmailAccount.cs @@ -0,0 +1,59 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common.models; + +namespace eSuite.API.Models; + +/// +/// +/// +public class ConfirmEmailAccount : IPasswordInformation +{ + /// + /// new password + /// + [Display(Name = "New Password")] + [DataType(DataType.Password)] + public string? Password { get; set; } = string.Empty; + + /// + /// new password entered again to ensure that the user hasn't made a mistake + /// + [Display(Name = "Confirm Password")] + [DataType(DataType.Password)] + [Compare(nameof(Password), ErrorMessage = "Passwords do not match")] + public string? ConfirmPassword { get; set; } = string.Empty; + + /// + /// Using Two factor authentication + /// + [Display(Name = "Using two factor authentication")] + [Required] + public bool UsingTwoFactorAuthentication { get; set; } = false; + + /// + /// Two factor authentication support settings - QR Code and manual token + /// + public TwoFactorAuthenticationSettings TwoFactorAuthenticationSettings { get; set; } = null!; + + /// + /// security code generated by authenticator application + /// + [Display(Name = "Authentication code")] + public string? SecurityCode { get; set; } = null!; + + /// + /// Sso login overridden by this being set + /// + public long? DomainSsoProviderId { get; set; } = null!; + + /// + /// Sso login method. -1 = password and optional 2FA, anything else is from the SsoPrividers list. + /// + [Display(Name = "Login Method")] + public long SsoProviderId { get; set; } = -1; + + /// + /// List of SSO Providers that the user can select. + /// + public Dictionary SsoProviders { get; set; } = []; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Models/EmailAddress.cs b/e-suite.API/eSuite.API/Models/EmailAddress.cs new file mode 100644 index 0000000..b3e2ed8 --- /dev/null +++ b/e-suite.API/eSuite.API/Models/EmailAddress.cs @@ -0,0 +1,19 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace eSuite.API.Models; + +/// +/// Used to as a parameter to pass an email address. +/// +public class EmailAddress +{ + /// + /// An email address + /// + [JsonPropertyName("email")] + [Required] + [DefaultValue("testuser@sun-strategy.com")] + public string Email { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Models/IPasswordInformation.cs b/e-suite.API/eSuite.API/Models/IPasswordInformation.cs new file mode 100644 index 0000000..c82db34 --- /dev/null +++ b/e-suite.API/eSuite.API/Models/IPasswordInformation.cs @@ -0,0 +1,59 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common.models; + +namespace eSuite.API.Models; + +/// +/// +/// +public interface IPasswordInformation +{ + /// + /// new password + /// + [Display(Name = "New Password")] + [DataType(DataType.Password)] + public string? Password { get; set; } + + /// + /// new password entered again to ensure that the user hasn't made a mistake + /// + [Display(Name = "Confirm Password")] + [DataType(DataType.Password)] + [Compare(nameof(Password), ErrorMessage = "Passwords do not match")] + public string? ConfirmPassword { get; set; } + + /// + /// Using Two factor authentication + /// + [Display(Name = "Using two factor authentication")] + [Required] + public bool UsingTwoFactorAuthentication { get; set; } + + /// + /// Two factor authentication support settings - QR Code and manual token + /// + public TwoFactorAuthenticationSettings TwoFactorAuthenticationSettings { get; set; } + + /// + /// security code generated by authenticator application + /// + [Display(Name = "Authentication code")] + public string? SecurityCode { get; set; } + + /// + /// Sso login overridden by this being set + /// + public long? DomainSsoProviderId { get; set; } + + /// + /// Sso login method. -1 = password and optional 2FA, anything else is from the SsoPrividers list. + /// + [Display(Name = "Login Method")] + public long SsoProviderId { get; set; } + + /// + /// List of SSO Providers that the user can select. + /// + public Dictionary SsoProviders { get; set; } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Models/SequenceIssueRequest.cs b/e-suite.API/eSuite.API/Models/SequenceIssueRequest.cs new file mode 100644 index 0000000..3f6c0e5 --- /dev/null +++ b/e-suite.API/eSuite.API/Models/SequenceIssueRequest.cs @@ -0,0 +1,26 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using eSuite.Core.Miscellaneous; + +namespace eSuite.API.Models; + +/// +/// Details needed in order to issue one or more sequence numbers. +/// +public class SequenceIssueRequest +{ + /// + /// Please supply the ID and/or the GUID (either or both is ok) + /// + [JsonPropertyName("generalIdRef")] + [Required] + public GeneralIdRef GeneralIdRef { get; set; } = new GeneralIdRef(); + + /// + /// number of sequence numbers to issue on this call. null will be assumed to be 1. + /// + [JsonPropertyName("count")] + [DefaultValue(1)] + public int Count { get; set; } = 1; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Models/SuccessfulLogin.cs b/e-suite.API/eSuite.API/Models/SuccessfulLogin.cs new file mode 100644 index 0000000..7ae59ef --- /dev/null +++ b/e-suite.API/eSuite.API/Models/SuccessfulLogin.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace eSuite.API.Models; + +/// +/// This will be returned when a new session has been successfully established. +/// +public class SuccessfulLogin +{ + /// + /// Title of the message stating that the login was successful. + /// + [JsonPropertyName("title")] + [Required] + public string Title { get; set; } = string.Empty; + + /// + /// The token to include in the bearer header to allow access to secure API calls. + /// + [JsonPropertyName("token")] + [Required] + public string Token { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Models/UserProfile.cs b/e-suite.API/eSuite.API/Models/UserProfile.cs new file mode 100644 index 0000000..3ce76d1 --- /dev/null +++ b/e-suite.API/eSuite.API/Models/UserProfile.cs @@ -0,0 +1,90 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common.models; + +namespace eSuite.API.Models; + +/// +/// User profile class used by the MVC User profile pages +/// +public class UserProfile : IPasswordInformation +{ + /// + /// First name + /// + [Display(Name = "First Name")] + public string? FirstName { get; set; } = string.Empty; + + /// + /// Middle names + /// + [Display(Name = "Middle Name(s)")] + public string? MiddleNames { get; set; } = string.Empty; + + /// + /// Last name + /// + [Display(Name = "Last Name")] + public string? LastName { get; set; } = string.Empty; + + /// + /// e-mail address + /// + [Required] + [EmailAddress] + [Display(Name = "E-Mail")] + public string Email { get; set; } = string.Empty; + + /// + /// new password + /// + [Display(Name = "New Password")] + [DataType(DataType.Password)] + public string? Password { get; set; } = string.Empty; + + /// + /// new password entered again to ensure that the user hasn't made a mistake + /// + [Display(Name = "Confirm Password")] + [DataType(DataType.Password)] + [Compare(nameof(Password), ErrorMessage = "Passwords do not match")] + public string? ConfirmPassword { get; set; } = string.Empty; + + /// + /// Using Two factor authentication + /// + [Display(Name = "Using two factor authentication")] + [Required] + public bool UsingTwoFactorAuthentication { get; set; } = false; + + /// + /// Two factor authentication support settings - QR Code and manual token + /// + public TwoFactorAuthenticationSettings TwoFactorAuthenticationSettings { get; set; } = null!; + + /// + /// security code generated by authenticator application + /// + [Display(Name = "Authentication code")] + public string? SecurityCode { get; set; } = null!; + + /// + /// Sso login overridden by this being set + /// + public long? DomainSsoProviderId { get; set; } + + /// + /// Sso login method. -1 = password and optional 2FA, anything else is from the SsoPrividers list. + /// + [Display(Name = "Login Method")] + public long SsoProviderId { get; set; } = -1; + + /// + /// SSO user Id + /// + public string SsoSubject { get; set; } = string.Empty; + + /// + /// List of SSO Providers that the user can select. + /// + public Dictionary SsoProviders { get; set; } = []; +} diff --git a/e-suite.API/eSuite.API/Program.cs b/e-suite.API/eSuite.API/Program.cs new file mode 100644 index 0000000..c5268e5 --- /dev/null +++ b/e-suite.API/eSuite.API/Program.cs @@ -0,0 +1,87 @@ +using Autofac; +using Autofac.Extensions.DependencyInjection; +using e_suite.Database.SqlServer; +using e_suite.Nuget.PasswordHasher; +using eSuite.API.DependencyInjection; +using eSuite.API.HealthChecks; +using eSuite.API.Middleware; +using eSuite.API.Swagger; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Swashbuckle.AspNetCore.SwaggerUI; +using System.Text.Json.Serialization; + +var builder = WebApplication.CreateBuilder(args); + +builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureContainer(builder => + { + builder.RegisterModule(new CoreRegistrationModule()); + }); + +// Add services to the container. + +//builder.Services.AddCors(options => +//{ +// options.AddDefaultPolicy( +// builder => +// { +// //todo lock this down +// //builder.WithOrigins("https://localhost") +// //.WithMethods("PUT", "DELETE", "GET", "POST"); +// builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); // allow any origin; +// }); +//}); + +builder.AddDatabaseContext(); +builder.AddTokenAuthentication(); +builder.Services.AddCustomPasswordHasher(builder.Configuration); +builder.Services.AddControllersWithViews() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + }); +builder.AddSwagger(); +builder.Services.AddHealthChecks() + .AddSqlServer(ESuiteDatabaseExtension.BuildConnectionString(builder.Configuration), name:"Database Server") + .AddDbContextCheck("Database Context") + .AddCheck("Mail Server", () => SmtpHealthCheck.Healthy(builder.Configuration, new SocketFactory())); +builder.Services.AddAntiforgery(options => options.HeaderName = "XSRF-TOKEN"); + +var app = builder.Build(); + +using (var scope = app.Services.CreateScope()) +{ + var services = scope.ServiceProvider; +} + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseStaticFiles(); + app.UseSwagger(); + app.UseSwaggerUI(o => + { + o.DocExpansion(DocExpansion.None); + o.InjectStylesheet("/swagger-ui/SwaggerDark.css"); + o.SwaggerEndpoint("/swagger/v1/swagger.json", "e-suite API"); + }); +} + +//app.UseCors(); +//app.UseMiddleware(); +//app.UseHttpsRedirection(); +app.MapHealthChecks("/healthz", new HealthCheckOptions //note: name healthz is intentional. https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-7.0 +{ + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse +}); +app.UseMiddleware(); + +app.UseAuthentication(); +app.UseAuthorization(); +app.UseMiddleware(); + +app.MapControllers().RequireAuthorization(); //This ensures that ALL API calls need a Bearer token, unless marked [AllowAnonymous] DO NOT REMOVE! + +app.Run(); diff --git a/e-suite.API/eSuite.API/Properties/launchSettings.json b/e-suite.API/eSuite.API/Properties/launchSettings.json new file mode 100644 index 0000000..c75f7e2 --- /dev/null +++ b/e-suite.API/eSuite.API/Properties/launchSettings.json @@ -0,0 +1,37 @@ +{ + "profiles": { + "eSuite.API": { + "commandName": "Project", + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:7066;http://localhost:5009", + "dotnetRunMessages": true + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:7066", + "sslPort": 44303 + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/CookieLink.cs b/e-suite.API/eSuite.API/SingleSignOn/CookieLink.cs new file mode 100644 index 0000000..d3d0d7d --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/CookieLink.cs @@ -0,0 +1,19 @@ +using e_suite.Database.Core.Tables.UserManager; + +namespace eSuite.API.SingleSignOn; + +/// +/// +/// +public class CookieLink +{ + /// + /// + /// + public User? User { get; set; } + + /// + /// + /// + public LinkType LinkType { get; set; } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/CookieManager.cs b/e-suite.API/eSuite.API/SingleSignOn/CookieManager.cs new file mode 100644 index 0000000..6c63806 --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/CookieManager.cs @@ -0,0 +1,199 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.API.Extensions; +using eSuite.API.Middleware; +using eSuite.Core.Miscellaneous; +using IUserManager = e_suite.API.Common.IUserManager; +// ReSharper disable All + +namespace eSuite.API.SingleSignOn; + +/// +/// Internal class used to manage cookies +/// +public class CookieManager : ICookieManager +{ + private readonly IUserManager _userManager; + + /// + /// Default constructor + /// + /// + public CookieManager(IUserManager userManager) + { + _userManager = userManager; + } + + private const string ssoNewUserLinkCookieName = "eSuiteNewUserLinkCookie"; + private const string ssoProfileLinkCookieName = "eSuiteProfileLinkCookie"; + private const string ssoIdCookieName = "eSuiteSsoProvider"; + + /// + /// Creates the session cookie with appropriate settings + /// + /// + /// + /// + public Task CreateSessionCookie(HttpResponse response, LoginResponse loginResponse) + { + response.Cookies.Append(AuthenticationExtension.SessionCookieName, loginResponse.Token, new CookieOptions + { + HttpOnly = false, //Set False as Javascript (React) needs to read the cookie. + SameSite = SameSiteMode.Strict, + Secure = true, + IsEssential = true, + Expires = null, //Session Cookie + Path = "/" + }); + return Task.CompletedTask; + } + + /// + /// Deletes any existing session cookie + /// + /// + /// + public Task DeleteSessionCookie(HttpResponse response) + { + response.Cookies.Delete(AuthenticationExtension.SessionCookieName); + return Task.CompletedTask; + } + + /// + /// Creates cookie used with an Sso Identity to a user account + /// + /// + /// + /// + /// + /// + public async Task CreateProfileLinkCookie(HttpResponse response, AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var guid = await _userManager.CreateSingleUseGuid(auditUserDetails, generalIdRef, cancellationToken); + + response.Cookies.Append(ssoProfileLinkCookieName, guid.ToString(), new CookieOptions + { + HttpOnly = true, //Set True only the server side app needs to know about this + SameSite = SameSiteMode.Lax, //Used when returning from an sso authorisation + Secure = true, + IsEssential = true, + Expires = null, //Session Cookie + Path = "/" + }); + } + + /// + /// Creates cookie used with an Sso Identity to a user account + /// + /// + /// + /// + /// + /// + public async Task CreateNewUserLinkCookie(HttpResponse response, AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var guid = await _userManager.CreateSingleUseGuid(auditUserDetails, generalIdRef, cancellationToken); + + response.Cookies.Append(ssoNewUserLinkCookieName, guid.ToString(), new CookieOptions + { + HttpOnly = true, //Set True only the server side app needs to know about this + SameSite = SameSiteMode.Lax, //Used when returning from an sso authorisation + Secure = true, + IsEssential = true, + Expires = null, //Session Cookie + Path = "/" + }); + } + + /// + /// Used to find a profile link cookie and find the appropriate user account + /// + /// + /// + /// + /// + public async Task GetUserIdFromLinkCookie(HttpRequest request, CancellationToken cancellationToken) + { + var cookieContent = string.Empty; + var cookieLink = new CookieLink() + { + LinkType = LinkType.None + }; + + if (request.Cookies.ContainsKey(ssoProfileLinkCookieName)) + { + cookieContent = request.Cookies[ssoProfileLinkCookieName] ?? throw new NotFoundException(); + cookieLink.LinkType = LinkType.Profile; + } + + if (request.Cookies.ContainsKey(ssoNewUserLinkCookieName)) + { + cookieContent = request.Cookies[ssoNewUserLinkCookieName] ?? throw new NotFoundException(); + cookieLink.LinkType = LinkType.NewUser; + } + + if (cookieLink.LinkType == LinkType.None) + { + return null; + } + + var guid = new Guid(cookieContent); + + cookieLink.User = await _userManager.GetUserWithSingleUseGuid(guid, cancellationToken); + return cookieLink; + } + + /// + /// Delete any existing Profile link cookie. + /// + /// + /// + public Task DeleteLinkCookie(HttpResponse response) + { + response.Cookies.Delete(ssoProfileLinkCookieName); + response.Cookies.Delete(ssoNewUserLinkCookieName); + return Task.CompletedTask; + } + + /// + /// Find the SsoProvider Id using a cookie to save user input + /// + /// + /// + public Task GetSsoIdFromSsoIdCookie(HttpRequest request) + { + return Task.FromResult(request.Cookies.ContainsKey(ssoIdCookieName) ? request.Cookies[ssoIdCookieName].ToLong() : null); + } + + /// + /// Delete the SsoProvider cookie as the user has manually logged out + /// + /// + /// + public Task DeleteSsoIdCookie(HttpResponse response) + { + response.Cookies.Delete(ssoIdCookieName); + return Task.CompletedTask; + } + + /// + /// Create the SsoProvider cookie, so that the login provess can be sped up for user convenience + /// + /// + /// + /// + public Task CreateSsoIdCookie(HttpResponse response, long ssoId) + { + response.Cookies.Append(ssoIdCookieName, ssoId.ToString(), new CookieOptions() + { + HttpOnly = true, + SameSite = SameSiteMode.Strict, + Secure = true, + IsEssential = true, + Expires = DateTime.UtcNow.AddMonths(1), //cookie will expire after a month. + Path = "/" + }); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/HttpClientFacade.cs b/e-suite.API/eSuite.API/SingleSignOn/HttpClientFacade.cs new file mode 100644 index 0000000..e09419a --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/HttpClientFacade.cs @@ -0,0 +1,31 @@ +namespace eSuite.API.SingleSignOn; + +/// +/// +/// +public class HttpClientFacade : IHttpClientFacade +{ + private readonly HttpClient _httpClient = new(); + + /// + /// + /// + /// + /// + /// + public async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await _httpClient.SendAsync(request, cancellationToken); + } + + /// + /// + /// + /// + /// + /// + public async Task GetStringAsync(Uri uri, CancellationToken cancellationToken) + { + return await _httpClient.GetStringAsync(uri, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/ICookieManager.cs b/e-suite.API/eSuite.API/SingleSignOn/ICookieManager.cs new file mode 100644 index 0000000..dd17f8f --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/ICookieManager.cs @@ -0,0 +1,84 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; + +namespace eSuite.API.SingleSignOn; + +/// +/// Used to create and remove cookies used by the application +/// +public interface ICookieManager +{ + /// + /// Creates a session cookie containing the users JWT Tokwn + /// + /// + /// + /// + Task CreateSessionCookie(HttpResponse response, LoginResponse loginResponse); + + /// + /// Removes the session cookie. + /// + /// + /// + Task DeleteSessionCookie(HttpResponse response); + + /// + /// Create a single use cookie used for linking a profile to an sso identity. + /// + /// + /// + /// + /// + /// + Task CreateProfileLinkCookie(HttpResponse response, AuditUserDetails auditUserDetails, GeneralIdRef id, CancellationToken cancellationToken); + + /// + /// Create a single use cookie used for linking a profile to an sso identity. + /// + /// + /// + /// + /// + /// + Task CreateNewUserLinkCookie(HttpResponse response, AuditUserDetails auditUserDetails, GeneralIdRef id, CancellationToken cancellationToken); + + + /// + /// Looks up the value of the single use cookie and converts it to a user for further processing + /// + /// + /// + /// + Task GetUserIdFromLinkCookie(HttpRequest request, CancellationToken cancellationToken); + + /// + /// Deletes the single use cookie + /// + /// + /// + Task DeleteLinkCookie(HttpResponse response); + + /// + /// Finds the current SSO Provider from the SsoId cookie, this cookie will remain in the browser between sessions + /// + /// + /// + Task GetSsoIdFromSsoIdCookie(HttpRequest request); + + /// + /// Create the SsoId cookie containing the provider ID, to help shorten the login process when using SSO + /// + /// + /// + /// + Task CreateSsoIdCookie(HttpResponse response, long ssoId); + + /// + /// Removes the SsoId cookie + /// + /// + /// + Task DeleteSsoIdCookie(HttpResponse response); +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/IHttpClientFacade.cs b/e-suite.API/eSuite.API/SingleSignOn/IHttpClientFacade.cs new file mode 100644 index 0000000..670b93d --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/IHttpClientFacade.cs @@ -0,0 +1,23 @@ +namespace eSuite.API.SingleSignOn; + +/// +/// +/// +public interface IHttpClientFacade +{ + /// + /// + /// + /// + /// + /// + Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); + + /// + /// + /// + /// + /// + /// + Task GetStringAsync(Uri uri, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/ISingleSignOn.cs b/e-suite.API/eSuite.API/SingleSignOn/ISingleSignOn.cs new file mode 100644 index 0000000..cd391b2 --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/ISingleSignOn.cs @@ -0,0 +1,32 @@ +namespace eSuite.API.SingleSignOn; + +/// +/// Internal type used for controlling the single sign on process +/// +public interface ISingleSignOn +{ + /// + /// Start single sign on using an e-mail address + /// + /// + /// + /// + Task StartSingleSignOn(string loginEmail, CancellationToken cancellationToken); + + /// + /// Start single sign on using an ssoProviderId + /// + /// + /// + /// + Task StartSingleSignOn(long ssoProviderId, CancellationToken cancellationToken); + + /// + /// Exchange the authorisation Token and return the SubjectId if successful. + /// + /// + /// + /// + /// + Task ExchangeAuthorisationToken(long ssoProviderId, string code, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/LinkType.cs b/e-suite.API/eSuite.API/SingleSignOn/LinkType.cs new file mode 100644 index 0000000..ed5986a --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/LinkType.cs @@ -0,0 +1,20 @@ +namespace eSuite.API.SingleSignOn; + +/// +/// +/// +public enum LinkType +{ + /// + /// + /// + None, + /// + /// + /// + NewUser, + /// + /// + /// + Profile +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/OpenIdConfiguration.cs b/e-suite.API/eSuite.API/SingleSignOn/OpenIdConfiguration.cs new file mode 100644 index 0000000..cbaddad --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/OpenIdConfiguration.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; + +namespace eSuite.API.SingleSignOn; + +/// +/// class used to deserialise the OpenId configuration Json +/// +public class OpenIdConfiguration +{ + /// + /// issuer of the tokens + /// + [JsonProperty("issuer")] + public string Issuer { get; set; } = string.Empty; + + /// + /// endpoint to use for authorisation requests + /// + [JsonProperty("authorization_endpoint")] + public string AuthorizationEndpoint { get; set; } = string.Empty; + + /// + /// uri for the jwks signatures used to verify JWT's. + /// + [JsonProperty("jwks_uri")] + public string JwksUri { get; set; } = string.Empty; + + //There are other members which are not current implemented in this class as I've not needed them. + //response_types_supported": [ "id_token", "token id_token" ], + //"subject_types_supported": [ "pairwise" ], + //"id_token_signing_alg_values_supported": [ "RS256" ], + //"claims_supported": [ "iss", ...] +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/OpenIdKeys.cs b/e-suite.API/eSuite.API/SingleSignOn/OpenIdKeys.cs new file mode 100644 index 0000000..6a3c07f --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/OpenIdKeys.cs @@ -0,0 +1,16 @@ +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; + +namespace eSuite.API.SingleSignOn; + +/// +/// OpenId keys used to verify JWT. +/// +public class OpenIdKeys +{ + /// + /// List of the currently value JWT Validation keys. + /// + [JsonProperty("keys")] + public List Keys { get; set; } = []; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/OpenIdResponse.cs b/e-suite.API/eSuite.API/SingleSignOn/OpenIdResponse.cs new file mode 100644 index 0000000..8e96936 --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/OpenIdResponse.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; + +namespace eSuite.API.SingleSignOn; + +/// +/// Used to convert an OpenId response Json to a class +/// +public class OpenIdResponse +{ + /// + /// Access token + /// + [JsonProperty("access_token")] + public string AccessToken { get; set; } = string.Empty; + + /// + /// how long until this class's content expires + /// + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + /// + /// scope of the authorisation given by the access token + /// + [JsonProperty("scope")] + public string Scope { get; set; } = string.Empty; + + /// + /// Token type + /// + [JsonProperty("token_type")] + public string TokenType { get; set; } = string.Empty; + + /// + /// id token + /// + [JsonProperty("id_token")] + public string IdToken { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/SingleSignOn/SingleSignOn.cs b/e-suite.API/eSuite.API/SingleSignOn/SingleSignOn.cs new file mode 100644 index 0000000..95ff916 --- /dev/null +++ b/e-suite.API/eSuite.API/SingleSignOn/SingleSignOn.cs @@ -0,0 +1,206 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Text; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.extensions; +using e_suite.Database.Core.Tables.UserManager; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; + +namespace eSuite.API.SingleSignOn; + +/// +/// Internal class used to manage the single sign on process +/// +public class SingleSignOn : ISingleSignOn +{ + private readonly e_suite.API.Common.IUserManager _userManager; + private readonly IConfiguration _configuration; + private readonly IHttpClientFacade _httpClientFacade; + + /// + /// Default constructor used for DI + /// + /// + /// + /// + public SingleSignOn(e_suite.API.Common.IUserManager userManager, IConfiguration configuration, IHttpClientFacade httpClientFacade) + { + _userManager = userManager; + _configuration = configuration; + _httpClientFacade = httpClientFacade; + } + + private readonly string _responseType = "code"; + private readonly string _scope = "openid"; + + private string GetRedirectUri(SsoProvider ssoProvider) + { + var redirectUri = _configuration.GetConfigValue("BASE_URL", "baseUrl", "http://localhost:3000"); + + return $"{redirectUri!.TrimEnd('/')}/account/auth/{ssoProvider.Id}"; + } + + /// + /// Use an e-mail address to find the appropriate sso provider and start the single sign on process. + /// + /// + /// + /// + public async Task StartSingleSignOn(string loginEmail, CancellationToken cancellationToken) + { + SsoProvider? ssoProvider; + try + { + ssoProvider = await GetSsoProviderByEmail(loginEmail, cancellationToken); + } + catch (NotFoundException) + { + ssoProvider = null; + } + + return BuildAuthorizationUrl(ssoProvider); + } + + /// + /// Use a known sso provider id to start the single sign on process. + /// + /// + /// + /// + /// + public async Task StartSingleSignOn(long ssoProviderId, CancellationToken cancellationToken) + { + var ssoProvider = await _userManager.GetSsoProviderById(ssoProviderId, cancellationToken) ?? + throw new NotFoundException("SSO Provider not found"); + + return BuildAuthorizationUrl(ssoProvider); + } + + private string BuildAuthorizationUrl(SsoProvider? ssoProvider) + { + if (ssoProvider == null) + return string.Empty; + + var authorizationUrl = + $"{ssoProvider.AuthorizationEndpoint}?response_type={_responseType}&client_id={ssoProvider.ClientId}&redirect_uri={GetRedirectUri(ssoProvider)}&scope={_scope}"; + return authorizationUrl; + } + + private async Task GetSsoProviderByEmail(string loginEmail, CancellationToken cancellationToken) + { + var ssoProvider = await _userManager.GetSsoProviderForEmail(loginEmail, cancellationToken) ?? throw new NotFoundException("SSO Provider Not Found"); + return ssoProvider; + } + + /// + /// Exchange the Authorisation Token for a Certified JWT and extract the Subject + /// + /// + /// + /// + /// + /// + public async Task ExchangeAuthorisationToken(long ssoProviderId, string code, CancellationToken cancellationToken) + { + var ssoProvider = await _userManager.GetSsoProviderById(ssoProviderId, cancellationToken) ?? throw new NotFoundException("SSO Provider Not Found"); + + var formFields = new Dictionary + { + { "grant_type", "authorization_code" }, + { "code", code }, + { "redirect_uri", GetRedirectUri(ssoProvider) }, + { "client_id", ssoProvider.ClientId }, + { "client_secret", ssoProvider.ClientSecret } + }; + + using var request = new HttpRequestMessage(HttpMethod.Post, ssoProvider.TokenEndpoint); + request.Content = new FormUrlEncodedContent(formFields); + using var response = await _httpClientFacade.SendAsync(request, cancellationToken); + var responseString = await response.Content.ReadAsStringAsync(cancellationToken); + var token = ExtractAccessTokenFromResponse(responseString); + + var ssoUserId = await ExtractSubjectFromJwt(ssoProvider, token, cancellationToken); + + return ssoUserId; + } + + private async Task ExtractSubjectFromJwt(SsoProvider ssoProvider, string token, CancellationToken cancellationToken) + { + var validatedToken = await ValidateToken(ssoProvider, token, cancellationToken); + + return validatedToken.Subject; + } + + /// + /// + /// + public string? ManualKey { get; set; } = null; + + private async Task ValidateToken(SsoProvider ssoProvider, string token, CancellationToken cancellationToken) + { + var securityToken = new JwtSecurityToken(token); + SecurityKey? key = await GetSecurityKey(ssoProvider, securityToken, cancellationToken); + + if (key == null) + { + if (ManualKey != null) + key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(ManualKey)); + } + + var tvp = new TokenValidationParameters + { + ValidateActor = false, // check the profile ID + + ValidateAudience = !string.IsNullOrWhiteSpace(ssoProvider.ClientId), + ValidAudience = ssoProvider.ClientId, + ValidateIssuer = true, + ValidIssuer = ssoProvider.ValidIssuer, + ValidateIssuerSigningKey = key != null, + IssuerSigningKey = key, + RequireSignedTokens = key != null, + ValidateLifetime = true, + RequireExpirationTime = true + }; + var handler = new JwtSecurityTokenHandler(); + handler.ValidateToken(token, tvp, out var validatedToken); + + if (validatedToken is JwtSecurityToken jwtSecurityToken) + { + return jwtSecurityToken; + } + + throw new ArgumentOutOfRangeException( nameof(token), "Invalid security token."); + + } + + private async Task GetSecurityKey(SsoProvider ssoProvider, JwtSecurityToken securityToken, CancellationToken cancellationToken) + { + var certificates = await GetCertificateDictionary(ssoProvider, cancellationToken); + if (certificates.Count == 0) + return null!; + var cert = certificates[securityToken.Header.Kid]; + return cert; + } + + private async Task> GetCertificateDictionary(SsoProvider ssoProvider, CancellationToken cancellationToken) + { + var openConfigurationUri = + new Uri($"{ssoProvider.ValidIssuer.TrimEnd('/')}/.well-known/openid-configuration"); + var configurationJson = await _httpClientFacade.GetStringAsync(openConfigurationUri, cancellationToken); + var openIdConfiguration = JsonConvert.DeserializeObject(configurationJson) ?? + throw new NullReferenceException(); + + var jwks = await _httpClientFacade.GetStringAsync(new Uri(openIdConfiguration.JwksUri), cancellationToken); + + var openIdKeys = JsonConvert.DeserializeObject(jwks)!; + + return openIdKeys.Keys.ToDictionary(key => key.Kid); + } + + private static string ExtractAccessTokenFromResponse(string responseString) + { + var responseJson = JsonConvert.DeserializeObject(responseString) ?? throw new NullReferenceException(); + + return responseJson.IdToken; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Swagger/HasAllowAnonymousOperationsFilter.cs b/e-suite.API/eSuite.API/Swagger/HasAllowAnonymousOperationsFilter.cs new file mode 100644 index 0000000..b3e4eda --- /dev/null +++ b/e-suite.API/eSuite.API/Swagger/HasAllowAnonymousOperationsFilter.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.OpenApi; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace eSuite.API.Swagger; + +internal class HasAllowAnonymousOperationsFilter : IOperationFilter +{ + public void Apply(OpenApiOperation operation, OperationFilterContext ctx) + { + if (ctx.ApiDescription.ActionDescriptor is ControllerActionDescriptor descriptor) + { + // If not [AllowAnonymous] and [Authorize] on either the endpoint or the controller... + if (!ctx.ApiDescription.CustomAttributes().Any((a) => a is AllowAnonymousAttribute)) + { + operation.Security = new List{ + new OpenApiSecurityRequirement { + { + new OpenApiSecuritySchemeReference( + "Bearer", + ctx.Document, + null + ), + [] + } + }}; + } + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Swagger/SwaggerExtension.cs b/e-suite.API/eSuite.API/Swagger/SwaggerExtension.cs new file mode 100644 index 0000000..7321a54 --- /dev/null +++ b/e-suite.API/eSuite.API/Swagger/SwaggerExtension.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using Microsoft.OpenApi; + +namespace eSuite.API.Swagger; + +internal static class SwaggerExtension +{ + /// + /// Adds support for Swagger documentation. + /// + /// + public static void AddSwagger(this WebApplicationBuilder builder) + { + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(options => + { + { + options.SwaggerDoc("v1", new OpenApiInfo + { + Version = "v1", + Title = "e-suite API", + Description = "The RESTful Web API for e-suite", + //TermsOfService = new Uri("https://example.com/terms"), + //Contact = new OpenApiContact + //{ + // Name = "Example Contact", + // Url = new Uri("https://example.com/contact") + //}, + //License = new OpenApiLicense + //{ + // Name = "License", + // Url = new Uri("https://example.com/license") + //} + }); + + options.OperationFilter(); + + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Please insert JWT with \"Bearer \" into field", + Name = "Authorization", + Type = SecuritySchemeType.ApiKey, + BearerFormat = "Bearer JWT" + }); + } + + var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); + } + ); + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Utilities/ClaimsPrincipalExtensions.cs b/e-suite.API/eSuite.API/Utilities/ClaimsPrincipalExtensions.cs new file mode 100644 index 0000000..58a7e5f --- /dev/null +++ b/e-suite.API/eSuite.API/Utilities/ClaimsPrincipalExtensions.cs @@ -0,0 +1,48 @@ +using System.Security.Claims; +using eSuite.Core.Miscellaneous; + +namespace eSuite.API.Utilities; + +/// +/// These methods are used to help make working with authenticated users easier +/// +internal static class ClaimsPrincipalExtensions +{ + /// + /// This gets the e-mail address of the current user. + /// + /// + /// email address from the JWT Token + public static string Email(this ClaimsPrincipal user) + { + return user.FindFirst(ClaimTypes.Email)?.Value!; + } + + /// + /// Gets the Internal DB user Id of the current user. + /// + /// + /// + public static long Id(this ClaimsPrincipal user) + { + return long.Parse(user.FindFirst(ClaimTypes.PrimarySid)?.Value!); + } + + public static GeneralIdRef GeneralIdRef(this ClaimsPrincipal user) + { + return new GeneralIdRef + { + Id = user.Id() + }; + } + + /// + /// Gets the Display name of the user as the time the Token was generated. + /// + /// + /// + public static string DisplayName(this ClaimsPrincipal user) + { + return user.FindFirst(ClaimTypes.Name)?.Value!; + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Utilities/ESuiteController.cs b/e-suite.API/eSuite.API/Utilities/ESuiteController.cs new file mode 100644 index 0000000..ef13299 --- /dev/null +++ b/e-suite.API/eSuite.API/Utilities/ESuiteController.cs @@ -0,0 +1,21 @@ +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Utilities; + +/// +/// MVC controller which also has supporting functions for the application. +/// +public class ESuiteController : Controller +{ + /// + /// Contains the details of the currently logged in user. This should be passed on to the audit module to make audit tracking easy. + /// + /// Set the comment property to include the comment into the audit log + protected AuditUserDetails AuditUserDetails => + new() + { + UserId = User.Id(), + UserDisplayName = User.DisplayName() + }; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Utilities/eSuiteControllerBase.cs b/e-suite.API/eSuite.API/Utilities/eSuiteControllerBase.cs new file mode 100644 index 0000000..0f8b0ed --- /dev/null +++ b/e-suite.API/eSuite.API/Utilities/eSuiteControllerBase.cs @@ -0,0 +1,21 @@ +using e_suite.Database.Audit; +using Microsoft.AspNetCore.Mvc; + +namespace eSuite.API.Utilities; + +/// +/// Base to use when adding a controller to the API +/// +public abstract class ESuiteControllerBase : ControllerBase +{ + /// + /// Contains the details of the currently logged in user. This should be passed on to the audit module to make audit tracking easy. + /// + /// Set the comment property to include the comment into the audit log + protected AuditUserDetails AuditUserDetails => + new() + { + UserId = User.Id(), + UserDisplayName = User.DisplayName() + }; +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/Views/Account/ConfirmAccount.cshtml b/e-suite.API/eSuite.API/Views/Account/ConfirmAccount.cshtml new file mode 100644 index 0000000..6152f56 --- /dev/null +++ b/e-suite.API/eSuite.API/Views/Account/ConfirmAccount.cshtml @@ -0,0 +1,22 @@ +@model eSuite.API.Models.ConfirmEmailAccount + +@{ + ViewBag.Title = "e-suite"; + Layout = "~/Views/Shared/_layout.cshtml"; +} + + +
+

Confirm Account

+ @using (Html.BeginForm(FormMethod.Post, true, null)) + { +
+ @Html.AntiForgeryToken() +
To activate your account, please enter a password
+ + @await Html.PartialAsync("_loginMethodChooser") + + +
+ } +
diff --git a/e-suite.API/eSuite.API/Views/Account/Login.cshtml b/e-suite.API/eSuite.API/Views/Account/Login.cshtml new file mode 100644 index 0000000..9e60f35 --- /dev/null +++ b/e-suite.API/eSuite.API/Views/Account/Login.cshtml @@ -0,0 +1,79 @@ +@using e_suite.API.Common.models +@model e_suite.API.Common.models.Login +@{ + ViewBag.Title = "e-suite"; + Layout = "~/Views/Shared/_layout.cshtml"; +} + + +
+

Login

+ @using (Html.BeginForm(FormMethod.Post, true, null)) + { +
+ @Html.AntiForgeryToken() + @switch (ViewBag.loginResponse) + { + case LoginResult.EmailNotConfirmed: +
Password reset e-mail has been sent.
+ Back to login + break; + case LoginResult.TwoFactorAuthenticationRemovalRequested: +
Two factor authentication removal has been requested
+ Back to login + break; + case LoginResult.TwoFactorAuthenticationCodeRequired: + case LoginResult.TwoFactorAuthenticationCodeIncorrect: + @Html.HiddenFor(m => m.Email) + @Html.HiddenFor(m => m.Password) + +
+ @Html.LabelFor(m => m.SecurityCode) +
+
+ @Html.EditorFor(m => m.SecurityCode, new { htmlAttributes = new { autocomplete = "one-time-code" } }) + @Html.ValidationMessageFor(m => m.Email) +
+ + + + break; + case LoginResult.Failed: + default: +
+ @Html.LabelFor(m => m.Email) +
+
+ @Html.EditorFor(m => m.Email, new { htmlAttributes = new { type = "email", autocomplete = "username" } }) + @Html.ValidationMessageFor(m => m.Email) +
+ + @if (Model.ForgotPassword) + { +
Password reset e-mail has been sent.
+ Back to login + } + else + { + @if (string.IsNullOrWhiteSpace(Model.Email)) + { + + } + else + { +
+ @Html.LabelFor(m => m.Password) +
+
+ @Html.EditorFor(m => m.Password, new { htmlAttributes = new { type = "password", autocomplete = "current-password" } }) + @Html.ValidationMessageFor(m => m.Password) +
+ + + } + } + break; + } +
+ } +
diff --git a/e-suite.API/eSuite.API/Views/Account/Profile.cshtml b/e-suite.API/eSuite.API/Views/Account/Profile.cshtml new file mode 100644 index 0000000..d8c84ab --- /dev/null +++ b/e-suite.API/eSuite.API/Views/Account/Profile.cshtml @@ -0,0 +1,46 @@ +@model eSuite.API.Models.UserProfile + +@{ + ViewBag.Title = "e-suite"; + Layout = "~/Views/Shared/_layout.cshtml"; +} + +
+

Profile

+ @using (Html.BeginForm(FormMethod.Post, true, null)) + { + @Html.AntiForgeryToken() +
+ @Html.LabelFor(m => m.Email) + @Html.EditorFor(m => m.Email, new { htmlAttributes = new + { + @class = "form-control", + @disabled = "disabled" + } }) + @Html.ValidationMessageFor(m => m.Email) +
+ +
+ @Html.LabelFor(m => m.FirstName) + @Html.EditorFor(m => m.FirstName, new { htmlAttributes = new { @class = "form-control" } }) + @Html.ValidationMessageFor(m => m.FirstName) +
+ +
+ @Html.LabelFor(m => m.MiddleNames) + @Html.EditorFor(m => m.MiddleNames, new { htmlAttributes = new { @class = "form-control" } }) + @Html.ValidationMessageFor(m => m.MiddleNames) +
+ +
+ @Html.LabelFor(m => m.LastName) + @Html.EditorFor(m => m.LastName, new { htmlAttributes = new { @class = "form-control" } }) + @Html.ValidationMessageFor(m => m.LastName) +
+ + @await Html.PartialAsync("_loginMethodChooser") + + + Home + } +
diff --git a/e-suite.API/eSuite.API/Views/Shared/_layout.cshtml b/e-suite.API/eSuite.API/Views/Shared/_layout.cshtml new file mode 100644 index 0000000..959a36c --- /dev/null +++ b/e-suite.API/eSuite.API/Views/Shared/_layout.cshtml @@ -0,0 +1,38 @@ + + +@* window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' *@ + + + + + + + + + + @ViewBag.Title + + + + + + + @RenderBody() + + diff --git a/e-suite.API/eSuite.API/Views/Shared/_loginMethodChooser.cshtml b/e-suite.API/eSuite.API/Views/Shared/_loginMethodChooser.cshtml new file mode 100644 index 0000000..630b02b --- /dev/null +++ b/e-suite.API/eSuite.API/Views/Shared/_loginMethodChooser.cshtml @@ -0,0 +1,206 @@ +@model eSuite.API.Models.IPasswordInformation + + +@if (Model.DomainSsoProviderId != null) +{ +
+ Your domain has authorisation from an external source. +
+} +else +{ +
+
+ @Html.LabelFor(m => m.SsoProviderId) + @Html.DropDownListFor(m => m.SsoProviderId, + new SelectList( + new List> + { + new(-1, "Password") + }.Concat(Model.SsoProviders.OrderBy(x => x.Value)), nameof(KeyValuePair.Key), nameof(KeyValuePair.Value))) +
+ +
+
+ @Html.LabelFor(m => m.Password) + @Html.EditorFor(m => m.Password, new + { + htmlAttributes = new + { + @class = "form-control", + autocomplete = "new-password" + } + }) + @Html.ValidationMessageFor(m => m.Password, default) +
+ +
Passwords require:
+
    +
  • At least 12 characters
  • +
  • At least 1 symbol
  • +
  • At least 1 number
  • +
  • At least 1 lowercase letter
  • +
  • At least 1 uppercase letter
  • +
+ +
+
+ @Html.LabelFor(m => m.ConfirmPassword) + @Html.EditorFor(m => m.ConfirmPassword, new + { + htmlAttributes = new + { + @class = "form-control", + autocomplete = "new-password" + } + }) + @Html.ValidationMessageFor(m => m.ConfirmPassword) +
+
+ +
+ @Html.LabelFor(m => m.UsingTwoFactorAuthentication) + @Html.EditorFor(m => m.UsingTwoFactorAuthentication, new { htmlAttributes = new { } }) + @Html.ValidationMessageFor(m => m.UsingTwoFactorAuthentication) +
+ +
+
+
+ +
+ +
+ @Model.TwoFactorAuthenticationSettings.ManualEntrySetupCode +
+
+ +
+ @Html.LabelFor(m => m.SecurityCode) + @Html.EditorFor(m => m.SecurityCode, new + { + htmlAttributes = new + { + @class = "form-control", + autocomplete = "one-time-code" + } + }) + @Html.ValidationMessageFor(m => m.SecurityCode) +
+
+
+
+ Save changes to trigger the process that will link your SSO Account. +
+
+} + + diff --git a/e-suite.API/eSuite.API/appsettings.Development.json b/e-suite.API/eSuite.API/appsettings.Development.json new file mode 100644 index 0000000..a6c4570 --- /dev/null +++ b/e-suite.API/eSuite.API/appsettings.Development.json @@ -0,0 +1,45 @@ +{ + "baseUrl": "http://localhost:3001", + "applicationName": "e-suite", + "https_port": 7066, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "database": { + "server": "(local)", + "databaseName": "esuite", + "encrypt": true, + "trustServerCertificate": true, + "username": "esuiteApplicationUser", + "password": "Plz change me on live, thank you" + }, + "JwtConfig": { + "secret": "Z8p9YKvYnwm62sPLJVdvp3M7bQ5l0UqRGwz95ZqL", + "expirationInMinutes": 15, + "audience": "localhost", + "issuer": "localhost" + }, + "Smtp": { + "Server": "127.0.0.1", + "Port": 25, + "FromAddress": "esuite@sun-strategy.com", + "FromDisplayName": "eSuite MailService", + "EmailTimeoutHours": 48 + }, + "RabbitMQ": { + "hostname": "localhost" + }, + "AuthConfig": { + "pepper": "ThisIsNotAGoodPepper" + }, + "Sentinel": { + "MaxLoginAttempts": 5, + "LoginAttemptTimeoutMinutes": 60 + }, + "twoFactorAuthentication": { + "keySize": 20 + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/appsettings.Production.json b/e-suite.API/eSuite.API/appsettings.Production.json new file mode 100644 index 0000000..2eead1a --- /dev/null +++ b/e-suite.API/eSuite.API/appsettings.Production.json @@ -0,0 +1,55 @@ +{ + "baseUrl": "http://localhost:3000", + "applicationName": "e-suite", + "https_port": 7066, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "database": { + "server": "(local)", + "databaseName": "esuite", + "encrypt": true, + "trustServerCertificate": true, + "username": "esuiteApplicationUser", + "password": "Plz change me on live, thank you" + }, + "JwtConfig": { + "secret": "Z8p9YKvYnwm62sPLJVdvp3M7bQ5l0UqRGwz95ZqL", + "expirationInMinutes": 15, + "audience": "localhost", + "issuer": "localhost" + }, + "Smtp": { + "Server": "host.docker.internal", + "Port": 25, + "FromAddress": "esuite@sun-strategy.com", + "FromDisplayName": "eSuite MailService", + "EmailTimeoutHours": 48 + }, + "RabbitMQ": { + "hostname": "host.docker.internal" + }, + "AuthConfig": { + "pepper": "ThisIsNotAGoodPepper" + }, + "Sentinel": { + "MaxLoginAttempts": 5, + "LoginAttemptTimeoutMinutes": 60 + }, + "twoFactorAuthentication": { + "keySize": 20 + }, + "Kestrel": { + "EndPoints": { + "Http": { + "Url": "http://+:80" + }, + "Https": { + "Url": "https://+:443" + } + } + } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/appsettings.json b/e-suite.API/eSuite.API/appsettings.json new file mode 100644 index 0000000..d2ba82f --- /dev/null +++ b/e-suite.API/eSuite.API/appsettings.json @@ -0,0 +1,20 @@ +{ + "Logging": { + "LogLevel": { // All providers, LogLevel applies to all the enabled providers. + "Default": "Error", // Default logging, Error and higher. + "Microsoft": "Warning" // All Microsoft* categories, Warning and higher. + }, + "Debug": { // Debug provider. + "LogLevel": { + "Default": "Information", // Overrides preceding LogLevel:Default setting. + "Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category. + } + }, + "EventSource": { // EventSource provider + "LogLevel": { + "Default": "Warning" // All categories of EventSource provider. + } + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/eSuite.API.csproj b/e-suite.API/eSuite.API/eSuite.API.csproj new file mode 100644 index 0000000..71b9595 --- /dev/null +++ b/e-suite.API/eSuite.API/eSuite.API.csproj @@ -0,0 +1,82 @@ + + + + net10.0 + enable + enable + aspnet-eSuite.API-EA26D200-BEDC-48D6-90C6-05928A9D2024 + + + + true + Linux + + + + False + + + + False + + + + + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + + + PreserveNewest + + + + diff --git a/e-suite.API/eSuite.API/security/AccessKeyAttribute.cs b/e-suite.API/eSuite.API/security/AccessKeyAttribute.cs new file mode 100644 index 0000000..49f7a2e --- /dev/null +++ b/e-suite.API/eSuite.API/security/AccessKeyAttribute.cs @@ -0,0 +1,24 @@ +using eSuite.Core.Security; + +namespace eSuite.API.security; + +/// +/// Used to quickly add support for security permissions to a method. +/// +[AttributeUsage(AttributeTargets.Method )] +public class AccessKeyAttribute : Attribute +{ + /// + /// + /// + /// + public AccessKeyAttribute(SecurityAccess securityAccess) + { + SecurityAccess = securityAccess; + } + + /// + /// + /// + public SecurityAccess SecurityAccess { get; } +} \ No newline at end of file diff --git a/e-suite.API/eSuite.API/wwwroot/swagger-ui/SwaggerDark.css b/e-suite.API/eSuite.API/wwwroot/swagger-ui/SwaggerDark.css new file mode 100644 index 0000000..70f2ebe --- /dev/null +++ b/e-suite.API/eSuite.API/wwwroot/swagger-ui/SwaggerDark.css @@ -0,0 +1,1331 @@ +@media only screen and (prefers-color-scheme: dark) { + a { + color: #8c8cfa; + } + + ::-webkit-scrollbar-track-piece { + background-color: rgba(255, 255, 255, .2) !important; + } + + ::-webkit-scrollbar-track { + background-color: rgba(255, 255, 255, .3) !important; + } + + ::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, .5) !important; + } + + embed[type="application/pdf"] { + filter: invert(90%); + } + + html { + background: #1f1f1f !important; + box-sizing: border-box; + filter: contrast(100%) brightness(100%) saturate(100%); + overflow-y: scroll; + } + + body { + background: #1f1f1f; + background-color: #1f1f1f; + background-image: none !important; + } + + button, input, select, textarea { + background-color: #1f1f1f; + color: #bfbfbf; + } + + font, html { + color: #bfbfbf; + } + + .swagger-ui, .swagger-ui section h3 { + color: #b5bac9; + } + + .swagger-ui a { + background-color: transparent; + } + + .swagger-ui mark { + background-color: #664b00; + color: #bfbfbf; + } + + .swagger-ui legend { + color: inherit; + } + + .swagger-ui .debug * { + outline: #e6da99 solid 1px; + } + + .swagger-ui .debug-white * { + outline: #fff solid 1px; + } + + .swagger-ui .debug-black * { + outline: #bfbfbf solid 1px; + } + + .swagger-ui .debug-grid { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) 0 0; + } + + .swagger-ui .debug-grid-16 { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODYyRjhERDU2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODYyRjhERDQ2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QTY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3QjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvCS01IAAABMSURBVHjaYmR4/5+BFPBfAMFm/MBgx8RAGWCn1AAmSg34Q6kBDKMGMDCwICeMIemF/5QawEipAWwUhwEjMDvbAWlWkvVBwu8vQIABAEwBCph8U6c0AAAAAElFTkSuQmCC) 0 0; + } + + .swagger-ui .debug-grid-8-solid { + background: url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAAAAD/4QMxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzExMSA3OS4xNTgzMjUsIDIwMTUvMDkvMTAtMDE6MTA6MjAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIxMjI0OTczNjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIxMjI0OTc0NjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjEyMjQ5NzE2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjEyMjQ5NzI2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAbGhopHSlBJiZBQi8vL0JHPz4+P0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHAR0pKTQmND8oKD9HPzU/R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0f/wAARCAAIAAgDASIAAhEBAxEB/8QAWQABAQAAAAAAAAAAAAAAAAAAAAYBAQEAAAAAAAAAAAAAAAAAAAIEEAEBAAMBAAAAAAAAAAAAAAABADECA0ERAAEDBQAAAAAAAAAAAAAAAAARITFBUWESIv/aAAwDAQACEQMRAD8AoOnTV1QTD7JJshP3vSM3P//Z) 0 0 #1c1c21; + } + + .swagger-ui .debug-grid-16-solid { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzY3MkJEN0U2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzY3MkJEN0Y2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3RDY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pve6J3kAAAAzSURBVHjaYvz//z8D0UDsMwMjSRoYP5Gq4SPNbRjVMEQ1fCRDg+in/6+J1AJUxsgAEGAA31BAJMS0GYEAAAAASUVORK5CYII=) 0 0 #1c1c21; + } + + .swagger-ui .b--black { + border-color: #000; + } + + .swagger-ui .b--near-black { + border-color: #121212; + } + + .swagger-ui .b--dark-gray { + border-color: #333; + } + + .swagger-ui .b--mid-gray { + border-color: #545454; + } + + .swagger-ui .b--gray { + border-color: #787878; + } + + .swagger-ui .b--silver { + border-color: #999; + } + + .swagger-ui .b--light-silver { + border-color: #6e6e6e; + } + + .swagger-ui .b--moon-gray { + border-color: #4d4d4d; + } + + .swagger-ui .b--light-gray { + border-color: #2b2b2b; + } + + .swagger-ui .b--near-white { + border-color: #242424; + } + + .swagger-ui .b--white { + border-color: #1c1c21; + } + + .swagger-ui .b--white-90 { + border-color: rgba(28, 28, 33, .9); + } + + .swagger-ui .b--white-80 { + border-color: rgba(28, 28, 33, .8); + } + + .swagger-ui .b--white-70 { + border-color: rgba(28, 28, 33, .7); + } + + .swagger-ui .b--white-60 { + border-color: rgba(28, 28, 33, .6); + } + + .swagger-ui .b--white-50 { + border-color: rgba(28, 28, 33, .5); + } + + .swagger-ui .b--white-40 { + border-color: rgba(28, 28, 33, .4); + } + + .swagger-ui .b--white-30 { + border-color: rgba(28, 28, 33, .3); + } + + .swagger-ui .b--white-20 { + border-color: rgba(28, 28, 33, .2); + } + + .swagger-ui .b--white-10 { + border-color: rgba(28, 28, 33, .1); + } + + .swagger-ui .b--white-05 { + border-color: rgba(28, 28, 33, .05); + } + + .swagger-ui .b--white-025 { + border-color: rgba(28, 28, 33, .024); + } + + .swagger-ui .b--white-0125 { + border-color: rgba(28, 28, 33, .01); + } + + .swagger-ui .b--black-90 { + border-color: rgba(0, 0, 0, .9); + } + + .swagger-ui .b--black-80 { + border-color: rgba(0, 0, 0, .8); + } + + .swagger-ui .b--black-70 { + border-color: rgba(0, 0, 0, .7); + } + + .swagger-ui .b--black-60 { + border-color: rgba(0, 0, 0, .6); + } + + .swagger-ui .b--black-50 { + border-color: rgba(0, 0, 0, .5); + } + + .swagger-ui .b--black-40 { + border-color: rgba(0, 0, 0, .4); + } + + .swagger-ui .b--black-30 { + border-color: rgba(0, 0, 0, .3); + } + + .swagger-ui .b--black-20 { + border-color: rgba(0, 0, 0, .2); + } + + .swagger-ui .b--black-10 { + border-color: rgba(0, 0, 0, .1); + } + + .swagger-ui .b--black-05 { + border-color: rgba(0, 0, 0, .05); + } + + .swagger-ui .b--black-025 { + border-color: rgba(0, 0, 0, .024); + } + + .swagger-ui .b--black-0125 { + border-color: rgba(0, 0, 0, .01); + } + + .swagger-ui .b--dark-red { + border-color: #bc2f36; + } + + .swagger-ui .b--red { + border-color: #c83932; + } + + .swagger-ui .b--light-red { + border-color: #ab3c2b; + } + + .swagger-ui .b--orange { + border-color: #cc6e33; + } + + .swagger-ui .b--purple { + border-color: #5e2ca5; + } + + .swagger-ui .b--light-purple { + border-color: #672caf; + } + + .swagger-ui .b--dark-pink { + border-color: #ab2b81; + } + + .swagger-ui .b--hot-pink { + border-color: #c03086; + } + + .swagger-ui .b--pink { + border-color: #8f2464; + } + + .swagger-ui .b--light-pink { + border-color: #721d4d; + } + + .swagger-ui .b--dark-green { + border-color: #1c6e50; + } + + .swagger-ui .b--green { + border-color: #279b70; + } + + .swagger-ui .b--light-green { + border-color: #228762; + } + + .swagger-ui .b--navy { + border-color: #0d1d35; + } + + .swagger-ui .b--dark-blue { + border-color: #20497e; + } + + .swagger-ui .b--blue { + border-color: #4380d0; + } + + .swagger-ui .b--light-blue { + border-color: #20517e; + } + + .swagger-ui .b--lightest-blue { + border-color: #143a52; + } + + .swagger-ui .b--washed-blue { + border-color: #0c312d; + } + + .swagger-ui .b--washed-green { + border-color: #0f3d2c; + } + + .swagger-ui .b--washed-red { + border-color: #411010; + } + + .swagger-ui .b--transparent { + border-color: transparent; + } + + .swagger-ui .b--gold, .swagger-ui .b--light-yellow, .swagger-ui .b--washed-yellow, .swagger-ui .b--yellow { + border-color: #664b00; + } + + .swagger-ui .shadow-1 { + box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; + } + + .swagger-ui .shadow-2 { + box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; + } + + .swagger-ui .shadow-3 { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; + } + + .swagger-ui .shadow-4 { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; + } + + .swagger-ui .shadow-5 { + box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; + } + + @media screen and (min-width: 30em) { + .swagger-ui .shadow-1-ns { + box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; + } + + .swagger-ui .shadow-2-ns { + box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; + } + + .swagger-ui .shadow-3-ns { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; + } + + .swagger-ui .shadow-4-ns { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; + } + + .swagger-ui .shadow-5-ns { + box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; + } + } + + @media screen and (max-width: 60em) and (min-width: 30em) { + .swagger-ui .shadow-1-m { + box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; + } + + .swagger-ui .shadow-2-m { + box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; + } + + .swagger-ui .shadow-3-m { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; + } + + .swagger-ui .shadow-4-m { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; + } + + .swagger-ui .shadow-5-m { + box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; + } + } + + @media screen and (min-width: 60em) { + .swagger-ui .shadow-1-l { + box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; + } + + .swagger-ui .shadow-2-l { + box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; + } + + .swagger-ui .shadow-3-l { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; + } + + .swagger-ui .shadow-4-l { + box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; + } + + .swagger-ui .shadow-5-l { + box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; + } + } + + .swagger-ui .black-05 { + color: rgba(191, 191, 191, .05); + } + + .swagger-ui .bg-black-05 { + background-color: rgba(0, 0, 0, .05); + } + + .swagger-ui .black-90, .swagger-ui .hover-black-90:focus, .swagger-ui .hover-black-90:hover { + color: rgba(191, 191, 191, .9); + } + + .swagger-ui .black-80, .swagger-ui .hover-black-80:focus, .swagger-ui .hover-black-80:hover { + color: rgba(191, 191, 191, .8); + } + + .swagger-ui .black-70, .swagger-ui .hover-black-70:focus, .swagger-ui .hover-black-70:hover { + color: rgba(191, 191, 191, .7); + } + + .swagger-ui .black-60, .swagger-ui .hover-black-60:focus, .swagger-ui .hover-black-60:hover { + color: rgba(191, 191, 191, .6); + } + + .swagger-ui .black-50, .swagger-ui .hover-black-50:focus, .swagger-ui .hover-black-50:hover { + color: rgba(191, 191, 191, .5); + } + + .swagger-ui .black-40, .swagger-ui .hover-black-40:focus, .swagger-ui .hover-black-40:hover { + color: rgba(191, 191, 191, .4); + } + + .swagger-ui .black-30, .swagger-ui .hover-black-30:focus, .swagger-ui .hover-black-30:hover { + color: rgba(191, 191, 191, .3); + } + + .swagger-ui .black-20, .swagger-ui .hover-black-20:focus, .swagger-ui .hover-black-20:hover { + color: rgba(191, 191, 191, .2); + } + + .swagger-ui .black-10, .swagger-ui .hover-black-10:focus, .swagger-ui .hover-black-10:hover { + color: rgba(191, 191, 191, .1); + } + + .swagger-ui .hover-white-90:focus, .swagger-ui .hover-white-90:hover, .swagger-ui .white-90 { + color: rgba(255, 255, 255, .9); + } + + .swagger-ui .hover-white-80:focus, .swagger-ui .hover-white-80:hover, .swagger-ui .white-80 { + color: rgba(255, 255, 255, .8); + } + + .swagger-ui .hover-white-70:focus, .swagger-ui .hover-white-70:hover, .swagger-ui .white-70 { + color: rgba(255, 255, 255, .7); + } + + .swagger-ui .hover-white-60:focus, .swagger-ui .hover-white-60:hover, .swagger-ui .white-60 { + color: rgba(255, 255, 255, .6); + } + + .swagger-ui .hover-white-50:focus, .swagger-ui .hover-white-50:hover, .swagger-ui .white-50 { + color: rgba(255, 255, 255, .5); + } + + .swagger-ui .hover-white-40:focus, .swagger-ui .hover-white-40:hover, .swagger-ui .white-40 { + color: rgba(255, 255, 255, .4); + } + + .swagger-ui .hover-white-30:focus, .swagger-ui .hover-white-30:hover, .swagger-ui .white-30 { + color: rgba(255, 255, 255, .3); + } + + .swagger-ui .hover-white-20:focus, .swagger-ui .hover-white-20:hover, .swagger-ui .white-20 { + color: rgba(255, 255, 255, .2); + } + + .swagger-ui .hover-white-10:focus, .swagger-ui .hover-white-10:hover, .swagger-ui .white-10 { + color: rgba(255, 255, 255, .1); + } + + .swagger-ui .hover-moon-gray:focus, .swagger-ui .hover-moon-gray:hover, .swagger-ui .moon-gray { + color: #ccc; + } + + .swagger-ui .hover-light-gray:focus, .swagger-ui .hover-light-gray:hover, .swagger-ui .light-gray { + color: #ededed; + } + + .swagger-ui .hover-near-white:focus, .swagger-ui .hover-near-white:hover, .swagger-ui .near-white { + color: #f5f5f5; + } + + .swagger-ui .dark-red, .swagger-ui .hover-dark-red:focus, .swagger-ui .hover-dark-red:hover { + color: #e6999d; + } + + .swagger-ui .hover-red:focus, .swagger-ui .hover-red:hover, .swagger-ui .red { + color: #e69d99; + } + + .swagger-ui .hover-light-red:focus, .swagger-ui .hover-light-red:hover, .swagger-ui .light-red { + color: #e6a399; + } + + .swagger-ui .hover-orange:focus, .swagger-ui .hover-orange:hover, .swagger-ui .orange { + color: #e6b699; + } + + .swagger-ui .gold, .swagger-ui .hover-gold:focus, .swagger-ui .hover-gold:hover { + color: #e6d099; + } + + .swagger-ui .hover-yellow:focus, .swagger-ui .hover-yellow:hover, .swagger-ui .yellow { + color: #e6da99; + } + + .swagger-ui .hover-light-yellow:focus, .swagger-ui .hover-light-yellow:hover, .swagger-ui .light-yellow { + color: #ede6b6; + } + + .swagger-ui .hover-purple:focus, .swagger-ui .hover-purple:hover, .swagger-ui .purple { + color: #b99ae4; + } + + .swagger-ui .hover-light-purple:focus, .swagger-ui .hover-light-purple:hover, .swagger-ui .light-purple { + color: #bb99e6; + } + + .swagger-ui .dark-pink, .swagger-ui .hover-dark-pink:focus, .swagger-ui .hover-dark-pink:hover { + color: #e699cc; + } + + .swagger-ui .hot-pink, .swagger-ui .hover-hot-pink:focus, .swagger-ui .hover-hot-pink:hover, .swagger-ui .hover-pink:focus, .swagger-ui .hover-pink:hover, .swagger-ui .pink { + color: #e699c7; + } + + .swagger-ui .hover-light-pink:focus, .swagger-ui .hover-light-pink:hover, .swagger-ui .light-pink { + color: #edb6d5; + } + + .swagger-ui .dark-green, .swagger-ui .green, .swagger-ui .hover-dark-green:focus, .swagger-ui .hover-dark-green:hover, .swagger-ui .hover-green:focus, .swagger-ui .hover-green:hover { + color: #99e6c9; + } + + .swagger-ui .hover-light-green:focus, .swagger-ui .hover-light-green:hover, .swagger-ui .light-green { + color: #a1e8ce; + } + + .swagger-ui .hover-navy:focus, .swagger-ui .hover-navy:hover, .swagger-ui .navy { + color: #99b8e6; + } + + .swagger-ui .blue, .swagger-ui .dark-blue, .swagger-ui .hover-blue:focus, .swagger-ui .hover-blue:hover, .swagger-ui .hover-dark-blue:focus, .swagger-ui .hover-dark-blue:hover { + color: #99bae6; + } + + .swagger-ui .hover-light-blue:focus, .swagger-ui .hover-light-blue:hover, .swagger-ui .light-blue { + color: #a9cbea; + } + + .swagger-ui .hover-lightest-blue:focus, .swagger-ui .hover-lightest-blue:hover, .swagger-ui .lightest-blue { + color: #d6e9f5; + } + + .swagger-ui .hover-washed-blue:focus, .swagger-ui .hover-washed-blue:hover, .swagger-ui .washed-blue { + color: #f7fdfc; + } + + .swagger-ui .hover-washed-green:focus, .swagger-ui .hover-washed-green:hover, .swagger-ui .washed-green { + color: #ebfaf4; + } + + .swagger-ui .hover-washed-yellow:focus, .swagger-ui .hover-washed-yellow:hover, .swagger-ui .washed-yellow { + color: #fbf9ef; + } + + .swagger-ui .hover-washed-red:focus, .swagger-ui .hover-washed-red:hover, .swagger-ui .washed-red { + color: #f9e7e7; + } + + .swagger-ui .color-inherit, .swagger-ui .hover-inherit:focus, .swagger-ui .hover-inherit:hover { + color: inherit; + } + + .swagger-ui .bg-black-90, .swagger-ui .hover-bg-black-90:focus, .swagger-ui .hover-bg-black-90:hover { + background-color: rgba(0, 0, 0, .9); + } + + .swagger-ui .bg-black-80, .swagger-ui .hover-bg-black-80:focus, .swagger-ui .hover-bg-black-80:hover { + background-color: rgba(0, 0, 0, .8); + } + + .swagger-ui .bg-black-70, .swagger-ui .hover-bg-black-70:focus, .swagger-ui .hover-bg-black-70:hover { + background-color: rgba(0, 0, 0, .7); + } + + .swagger-ui .bg-black-60, .swagger-ui .hover-bg-black-60:focus, .swagger-ui .hover-bg-black-60:hover { + background-color: rgba(0, 0, 0, .6); + } + + .swagger-ui .bg-black-50, .swagger-ui .hover-bg-black-50:focus, .swagger-ui .hover-bg-black-50:hover { + background-color: rgba(0, 0, 0, .5); + } + + .swagger-ui .bg-black-40, .swagger-ui .hover-bg-black-40:focus, .swagger-ui .hover-bg-black-40:hover { + background-color: rgba(0, 0, 0, .4); + } + + .swagger-ui .bg-black-30, .swagger-ui .hover-bg-black-30:focus, .swagger-ui .hover-bg-black-30:hover { + background-color: rgba(0, 0, 0, .3); + } + + .swagger-ui .bg-black-20, .swagger-ui .hover-bg-black-20:focus, .swagger-ui .hover-bg-black-20:hover { + background-color: rgba(0, 0, 0, .2); + } + + .swagger-ui .bg-white-90, .swagger-ui .hover-bg-white-90:focus, .swagger-ui .hover-bg-white-90:hover { + background-color: rgba(28, 28, 33, .9); + } + + .swagger-ui .bg-white-80, .swagger-ui .hover-bg-white-80:focus, .swagger-ui .hover-bg-white-80:hover { + background-color: rgba(28, 28, 33, .8); + } + + .swagger-ui .bg-white-70, .swagger-ui .hover-bg-white-70:focus, .swagger-ui .hover-bg-white-70:hover { + background-color: rgba(28, 28, 33, .7); + } + + .swagger-ui .bg-white-60, .swagger-ui .hover-bg-white-60:focus, .swagger-ui .hover-bg-white-60:hover { + background-color: rgba(28, 28, 33, .6); + } + + .swagger-ui .bg-white-50, .swagger-ui .hover-bg-white-50:focus, .swagger-ui .hover-bg-white-50:hover { + background-color: rgba(28, 28, 33, .5); + } + + .swagger-ui .bg-white-40, .swagger-ui .hover-bg-white-40:focus, .swagger-ui .hover-bg-white-40:hover { + background-color: rgba(28, 28, 33, .4); + } + + .swagger-ui .bg-white-30, .swagger-ui .hover-bg-white-30:focus, .swagger-ui .hover-bg-white-30:hover { + background-color: rgba(28, 28, 33, .3); + } + + .swagger-ui .bg-white-20, .swagger-ui .hover-bg-white-20:focus, .swagger-ui .hover-bg-white-20:hover { + background-color: rgba(28, 28, 33, .2); + } + + .swagger-ui .bg-black, .swagger-ui .hover-bg-black:focus, .swagger-ui .hover-bg-black:hover { + background-color: #000; + } + + .swagger-ui .bg-near-black, .swagger-ui .hover-bg-near-black:focus, .swagger-ui .hover-bg-near-black:hover { + background-color: #121212; + } + + .swagger-ui .bg-dark-gray, .swagger-ui .hover-bg-dark-gray:focus, .swagger-ui .hover-bg-dark-gray:hover { + background-color: #333; + } + + .swagger-ui .bg-mid-gray, .swagger-ui .hover-bg-mid-gray:focus, .swagger-ui .hover-bg-mid-gray:hover { + background-color: #545454; + } + + .swagger-ui .bg-gray, .swagger-ui .hover-bg-gray:focus, .swagger-ui .hover-bg-gray:hover { + background-color: #787878; + } + + .swagger-ui .bg-silver, .swagger-ui .hover-bg-silver:focus, .swagger-ui .hover-bg-silver:hover { + background-color: #999; + } + + .swagger-ui .bg-white, .swagger-ui .hover-bg-white:focus, .swagger-ui .hover-bg-white:hover { + background-color: #1c1c21; + } + + .swagger-ui .bg-transparent, .swagger-ui .hover-bg-transparent:focus, .swagger-ui .hover-bg-transparent:hover { + background-color: transparent; + } + + .swagger-ui .bg-dark-red, .swagger-ui .hover-bg-dark-red:focus, .swagger-ui .hover-bg-dark-red:hover { + background-color: #bc2f36; + } + + .swagger-ui .bg-red, .swagger-ui .hover-bg-red:focus, .swagger-ui .hover-bg-red:hover { + background-color: #c83932; + } + + .swagger-ui .bg-light-red, .swagger-ui .hover-bg-light-red:focus, .swagger-ui .hover-bg-light-red:hover { + background-color: #ab3c2b; + } + + .swagger-ui .bg-orange, .swagger-ui .hover-bg-orange:focus, .swagger-ui .hover-bg-orange:hover { + background-color: #cc6e33; + } + + .swagger-ui .bg-gold, .swagger-ui .bg-light-yellow, .swagger-ui .bg-washed-yellow, .swagger-ui .bg-yellow, .swagger-ui .hover-bg-gold:focus, .swagger-ui .hover-bg-gold:hover, .swagger-ui .hover-bg-light-yellow:focus, .swagger-ui .hover-bg-light-yellow:hover, .swagger-ui .hover-bg-washed-yellow:focus, .swagger-ui .hover-bg-washed-yellow:hover, .swagger-ui .hover-bg-yellow:focus, .swagger-ui .hover-bg-yellow:hover { + background-color: #664b00; + } + + .swagger-ui .bg-purple, .swagger-ui .hover-bg-purple:focus, .swagger-ui .hover-bg-purple:hover { + background-color: #5e2ca5; + } + + .swagger-ui .bg-light-purple, .swagger-ui .hover-bg-light-purple:focus, .swagger-ui .hover-bg-light-purple:hover { + background-color: #672caf; + } + + .swagger-ui .bg-dark-pink, .swagger-ui .hover-bg-dark-pink:focus, .swagger-ui .hover-bg-dark-pink:hover { + background-color: #ab2b81; + } + + .swagger-ui .bg-hot-pink, .swagger-ui .hover-bg-hot-pink:focus, .swagger-ui .hover-bg-hot-pink:hover { + background-color: #c03086; + } + + .swagger-ui .bg-pink, .swagger-ui .hover-bg-pink:focus, .swagger-ui .hover-bg-pink:hover { + background-color: #8f2464; + } + + .swagger-ui .bg-light-pink, .swagger-ui .hover-bg-light-pink:focus, .swagger-ui .hover-bg-light-pink:hover { + background-color: #721d4d; + } + + .swagger-ui .bg-dark-green, .swagger-ui .hover-bg-dark-green:focus, .swagger-ui .hover-bg-dark-green:hover { + background-color: #1c6e50; + } + + .swagger-ui .bg-green, .swagger-ui .hover-bg-green:focus, .swagger-ui .hover-bg-green:hover { + background-color: #279b70; + } + + .swagger-ui .bg-light-green, .swagger-ui .hover-bg-light-green:focus, .swagger-ui .hover-bg-light-green:hover { + background-color: #228762; + } + + .swagger-ui .bg-navy, .swagger-ui .hover-bg-navy:focus, .swagger-ui .hover-bg-navy:hover { + background-color: #0d1d35; + } + + .swagger-ui .bg-dark-blue, .swagger-ui .hover-bg-dark-blue:focus, .swagger-ui .hover-bg-dark-blue:hover { + background-color: #20497e; + } + + .swagger-ui .bg-blue, .swagger-ui .hover-bg-blue:focus, .swagger-ui .hover-bg-blue:hover { + background-color: #4380d0; + } + + .swagger-ui .bg-light-blue, .swagger-ui .hover-bg-light-blue:focus, .swagger-ui .hover-bg-light-blue:hover { + background-color: #20517e; + } + + .swagger-ui .bg-lightest-blue, .swagger-ui .hover-bg-lightest-blue:focus, .swagger-ui .hover-bg-lightest-blue:hover { + background-color: #143a52; + } + + .swagger-ui .bg-washed-blue, .swagger-ui .hover-bg-washed-blue:focus, .swagger-ui .hover-bg-washed-blue:hover { + background-color: #0c312d; + } + + .swagger-ui .bg-washed-green, .swagger-ui .hover-bg-washed-green:focus, .swagger-ui .hover-bg-washed-green:hover { + background-color: #0f3d2c; + } + + .swagger-ui .bg-washed-red, .swagger-ui .hover-bg-washed-red:focus, .swagger-ui .hover-bg-washed-red:hover { + background-color: #411010; + } + + .swagger-ui .bg-inherit, .swagger-ui .hover-bg-inherit:focus, .swagger-ui .hover-bg-inherit:hover { + background-color: inherit; + } + + .swagger-ui .shadow-hover { + transition: all .5s cubic-bezier(.165, .84, .44, 1) 0s; + } + + .swagger-ui .shadow-hover::after { + border-radius: inherit; + box-shadow: rgba(0, 0, 0, .2) 0 0 16px 2px; + content: ""; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + transition: opacity .5s cubic-bezier(.165, .84, .44, 1) 0s; + width: 100%; + z-index: -1; + } + + .swagger-ui .bg-animate, .swagger-ui .bg-animate:focus, .swagger-ui .bg-animate:hover { + transition: background-color .15s ease-in-out 0s; + } + + .swagger-ui .nested-links a { + color: #99bae6; + transition: color .15s ease-in 0s; + } + + .swagger-ui .nested-links a:focus, .swagger-ui .nested-links a:hover { + color: #a9cbea; + transition: color .15s ease-in 0s; + } + + .swagger-ui .opblock-tag { + border-bottom: 1px solid rgba(58, 64, 80, .3); + color: #b5bac9; + transition: all .2s ease 0s; + } + + .swagger-ui .opblock-tag svg, .swagger-ui section.models h4 svg { + transition: all .4s ease 0s; + } + + .swagger-ui .opblock { + border: 1px solid #000; + border-radius: 4px; + box-shadow: rgba(0, 0, 0, .19) 0 0 3px; + margin: 0 0 15px; + } + + .swagger-ui .opblock .tab-header .tab-item.active h4 span::after { + background: gray; + } + + .swagger-ui .opblock.is-open .opblock-summary { + border-bottom: 1px solid #000; + } + + .swagger-ui .opblock .opblock-section-header { + background: rgba(28, 28, 33, .8); + box-shadow: rgba(0, 0, 0, .1) 0 1px 2px; + } + + .swagger-ui .opblock .opblock-section-header > label > span { + padding: 0 10px 0 0; + } + + .swagger-ui .opblock .opblock-summary-method { + background: #000; + color: #fff; + text-shadow: rgba(0, 0, 0, .1) 0 1px 0; + } + + .swagger-ui .opblock.opblock-post { + background: rgba(72, 203, 144, .1); + border-color: #48cb90; + } + + .swagger-ui .opblock.opblock-post .opblock-summary-method, .swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span::after { + background: #48cb90; + } + + .swagger-ui .opblock.opblock-post .opblock-summary { + border-color: #48cb90; + } + + .swagger-ui .opblock.opblock-put { + background: rgba(213, 157, 88, .1); + border-color: #d59d58; + } + + .swagger-ui .opblock.opblock-put .opblock-summary-method, .swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span::after { + background: #d59d58; + } + + .swagger-ui .opblock.opblock-put .opblock-summary { + border-color: #d59d58; + } + + .swagger-ui .opblock.opblock-delete { + background: rgba(200, 50, 50, .1); + border-color: #c83232; + } + + .swagger-ui .opblock.opblock-delete .opblock-summary-method, .swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span::after { + background: #c83232; + } + + .swagger-ui .opblock.opblock-delete .opblock-summary { + border-color: #c83232; + } + + .swagger-ui .opblock.opblock-get { + background: rgba(42, 105, 167, .1); + border-color: #2a69a7; + } + + .swagger-ui .opblock.opblock-get .opblock-summary-method, .swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span::after { + background: #2a69a7; + } + + .swagger-ui .opblock.opblock-get .opblock-summary { + border-color: #2a69a7; + } + + .swagger-ui .opblock.opblock-patch { + background: rgba(92, 214, 188, .1); + border-color: #5cd6bc; + } + + .swagger-ui .opblock.opblock-patch .opblock-summary-method, .swagger-ui .opblock.opblock-patch .tab-header .tab-item.active h4 span::after { + background: #5cd6bc; + } + + .swagger-ui .opblock.opblock-patch .opblock-summary { + border-color: #5cd6bc; + } + + .swagger-ui .opblock.opblock-head { + background: rgba(140, 63, 207, .1); + border-color: #8c3fcf; + } + + .swagger-ui .opblock.opblock-head .opblock-summary-method, .swagger-ui .opblock.opblock-head .tab-header .tab-item.active h4 span::after { + background: #8c3fcf; + } + + .swagger-ui .opblock.opblock-head .opblock-summary { + border-color: #8c3fcf; + } + + .swagger-ui .opblock.opblock-options { + background: rgba(36, 89, 143, .1); + border-color: #24598f; + } + + .swagger-ui .opblock.opblock-options .opblock-summary-method, .swagger-ui .opblock.opblock-options .tab-header .tab-item.active h4 span::after { + background: #24598f; + } + + .swagger-ui .opblock.opblock-options .opblock-summary { + border-color: #24598f; + } + + .swagger-ui .opblock.opblock-deprecated { + background: rgba(46, 46, 46, .1); + border-color: #2e2e2e; + opacity: .6; + } + + .swagger-ui .opblock.opblock-deprecated .opblock-summary-method, .swagger-ui .opblock.opblock-deprecated .tab-header .tab-item.active h4 span::after { + background: #2e2e2e; + } + + .swagger-ui .opblock.opblock-deprecated .opblock-summary { + border-color: #2e2e2e; + } + + .swagger-ui .filter .operation-filter-input { + border: 2px solid #2b3446; + } + + .swagger-ui .tab li:first-of-type::after { + background: rgba(0, 0, 0, .2); + } + + .swagger-ui .download-contents { + background: #7c8192; + color: #fff; + } + + .swagger-ui .scheme-container { + background: #1c1c21; + box-shadow: rgba(0, 0, 0, .15) 0 1px 2px 0; + } + + .swagger-ui .loading-container .loading::before { + animation: 1s linear 0s infinite normal none running rotation, .5s ease 0s 1 normal none running opacity; + border-color: rgba(0, 0, 0, .6) rgba(84, 84, 84, .1) rgba(84, 84, 84, .1); + } + + .swagger-ui .response-control-media-type--accept-controller select { + border-color: #196619; + } + + .swagger-ui .response-control-media-type__accept-message { + color: #99e699; + } + + .swagger-ui .version-pragma__message code { + background-color: #3b3b3b; + } + + .swagger-ui .btn { + background: 0 0; + border: 2px solid gray; + box-shadow: rgba(0, 0, 0, .1) 0 1px 2px; + color: #b5bac9; + } + + .swagger-ui .btn:hover { + box-shadow: rgba(0, 0, 0, .3) 0 0 5px; + } + + .swagger-ui .btn.authorize, .swagger-ui .btn.cancel { + background-color: transparent; + border-color: #a72a2a; + color: #e69999; + } + + .swagger-ui .btn.authorize { + border-color: #48cb90; + color: #9ce3c3; + } + + .swagger-ui .btn.authorize svg { + fill: #9ce3c3; + } + + .swagger-ui .btn.execute { + background-color: #5892d5; + border-color: #5892d5; + color: #fff; + } + + .swagger-ui .copy-to-clipboard { + background: #7c8192; + } + + .swagger-ui .copy-to-clipboard button { + background: url("data:image/svg+xml;charset=utf-8,") 50% center no-repeat; + } + + .swagger-ui select { + background: url("data:image/svg+xml;charset=utf-8,") right 10px center/20px no-repeat #212121; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4wICg0MDM1YTRmYjQ5LCAyMDIwLTA1LTAxKSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iZG93bmxvYWQuc3ZnIgogICBpZD0ic3ZnNCIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMjAgMjAiPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTEwIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZGVmcwogICAgIGlkPSJkZWZzOCIgLz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnNCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6Y3k9IjEwIgogICAgIGlua3NjYXBlOmN4PSIxMCIKICAgICBpbmtzY2FwZTp6b29tPSI0MS41IgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpZD0ibmFtZWR2aWV3NiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDAxIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGd1aWRldG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBvYmplY3R0b2xlcmFuY2U9IjEwIgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAvPgogIDxwYXRoCiAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZiIKICAgICBpZD0icGF0aDIiCiAgICAgZD0iTTEzLjQxOCA3Ljg1OWEuNjk1LjY5NSAwIDAxLjk3OCAwIC42OC42OCAwIDAxMCAuOTY5bC0zLjkwOCAzLjgzYS42OTcuNjk3IDAgMDEtLjk3OSAwbC0zLjkwOC0zLjgzYS42OC42OCAwIDAxMC0uOTY5LjY5NS42OTUgMCAwMS45NzggMEwxMCAxMWwzLjQxOC0zLjE0MXoiIC8+Cjwvc3ZnPgo=) right 10px center/20px no-repeat #1c1c21; + border: 2px solid #41444e; + } + + .swagger-ui select[multiple] { + background: #212121; + } + + .swagger-ui button.invalid, .swagger-ui input[type=email].invalid, .swagger-ui input[type=file].invalid, .swagger-ui input[type=password].invalid, .swagger-ui input[type=search].invalid, .swagger-ui input[type=text].invalid, .swagger-ui select.invalid, .swagger-ui textarea.invalid { + background: #390e0e; + border-color: #c83232; + } + + .swagger-ui input[type=email], .swagger-ui input[type=file], .swagger-ui input[type=password], .swagger-ui input[type=search], .swagger-ui input[type=text], .swagger-ui textarea { + background: #1c1c21; + border: 1px solid #404040; + } + + .swagger-ui textarea { + background: rgba(28, 28, 33, .8); + color: #b5bac9; + } + + .swagger-ui input[disabled], .swagger-ui select[disabled] { + background-color: #1f1f1f; + color: #bfbfbf; + } + + .swagger-ui textarea[disabled] { + background-color: #41444e; + color: #fff; + } + + .swagger-ui select[disabled] { + border-color: #878787; + } + + .swagger-ui textarea:focus { + border: 2px solid #2a69a7; + } + + .swagger-ui .checkbox input[type=checkbox] + label > .item { + background: #303030; + box-shadow: #303030 0 0 0 2px; + } + + .swagger-ui .checkbox input[type=checkbox]:checked + label > .item { + background: url("data:image/svg+xml;charset=utf-8,") 50% center no-repeat #303030; + } + + .swagger-ui .dialog-ux .backdrop-ux { + background: rgba(0, 0, 0, .8); + } + + .swagger-ui .dialog-ux .modal-ux { + background: #1c1c21; + border: 1px solid #2e2e2e; + box-shadow: rgba(0, 0, 0, .2) 0 10px 30px 0; + } + + .swagger-ui .dialog-ux .modal-ux-header .close-modal { + background: 0 0; + } + + .swagger-ui .model .deprecated span, .swagger-ui .model .deprecated td { + color: #bfbfbf !important; + } + + .swagger-ui .model-toggle::after { + background: url("data:image/svg+xml;charset=utf-8,") 50% center/100% no-repeat; + } + + .swagger-ui .model-hint { + background: rgba(0, 0, 0, .7); + color: #ebebeb; + } + + .swagger-ui section.models { + border: 1px solid rgba(58, 64, 80, .3); + } + + .swagger-ui section.models.is-open h4 { + border-bottom: 1px solid rgba(58, 64, 80, .3); + } + + .swagger-ui section.models .model-container { + background: rgba(0, 0, 0, .05); + } + + .swagger-ui section.models .model-container:hover { + background: rgba(0, 0, 0, .07); + } + + .swagger-ui .model-box { + background: rgba(0, 0, 0, .1); + } + + .swagger-ui .prop-type { + color: #aaaad4; + } + + .swagger-ui table thead tr td, .swagger-ui table thead tr th { + border-bottom: 1px solid rgba(58, 64, 80, .2); + color: #b5bac9; + } + + .swagger-ui .parameter__name.required::after { + color: rgba(230, 153, 153, .6); + } + + .swagger-ui .topbar .download-url-wrapper .select-label { + color: #f0f0f0; + } + + .swagger-ui .topbar .download-url-wrapper .download-url-button { + background: #63a040; + color: #fff; + } + + .swagger-ui .info .title small { + background: #7c8492; + } + + .swagger-ui .info .title small.version-stamp { + background-color: #7a9b27; + } + + .swagger-ui .auth-container .errors { + background-color: #350d0d; + color: #b5bac9; + } + + .swagger-ui .errors-wrapper { + background: rgba(200, 50, 50, .1); + border: 2px solid #c83232; + } + + .swagger-ui .markdown code, .swagger-ui .renderedmarkdown code { + background: rgba(0, 0, 0, .05); + color: #c299e6; + } + + .swagger-ui .model-toggle:after { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4wICg0MDM1YTRmYjQ5LCAyMDIwLTA1LTAxKSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iZG93bmxvYWQyLnN2ZyIKICAgaWQ9InN2ZzQiCiAgIHZlcnNpb249IjEuMSIKICAgaGVpZ2h0PSIyNCIKICAgd2lkdGg9IjI0Ij4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGExMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGRlZnMKICAgICBpZD0iZGVmczgiIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9InN2ZzQiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOmN5PSIxMiIKICAgICBpbmtzY2FwZTpjeD0iMTIiCiAgICAgaW5rc2NhcGU6em9vbT0iMzQuNTgzMzMzIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpZD0ibmFtZWR2aWV3NiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDAxIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGd1aWRldG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBvYmplY3R0b2xlcmFuY2U9IjEwIgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAvPgogIDxwYXRoCiAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZiIKICAgICBpZD0icGF0aDIiCiAgICAgZD0iTTEwIDZMOC41OSA3LjQxIDEzLjE3IDEybC00LjU4IDQuNTlMMTAgMThsNi02eiIgLz4KPC9zdmc+Cg==) 50% no-repeat; + } + + .swagger-ui .expand-operation svg, .swagger-ui section.models h4 svg { + fill: #fff; + } + + ::-webkit-scrollbar-track { + background-color: #646464 !important; + } + + ::-webkit-scrollbar-thumb { + background-color: #242424 !important; + border: 2px solid #3e4346 !important; + } + + ::-webkit-scrollbar-button:vertical:start:decrement { + background: linear-gradient(130deg, #696969 40%, rgba(255, 0, 0, 0) 41%), linear-gradient(230deg, #696969 40%, transparent 41%), linear-gradient(0deg, #696969 40%, transparent 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button:vertical:end:increment { + background: linear-gradient(310deg, #696969 40%, transparent 41%), linear-gradient(50deg, #696969 40%, transparent 41%), linear-gradient(180deg, #696969 40%, transparent 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button:horizontal:end:increment { + background: linear-gradient(210deg, #696969 40%, transparent 41%), linear-gradient(330deg, #696969 40%, transparent 41%), linear-gradient(90deg, #696969 30%, transparent 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button:horizontal:start:decrement { + background: linear-gradient(30deg, #696969 40%, transparent 41%), linear-gradient(150deg, #696969 40%, transparent 41%), linear-gradient(270deg, #696969 30%, transparent 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button, ::-webkit-scrollbar-track-piece { + background-color: #3e4346 !important; + } + + .swagger-ui .black, .swagger-ui .checkbox, .swagger-ui .dark-gray, .swagger-ui .download-url-wrapper .loading, .swagger-ui .errors-wrapper .errors small, .swagger-ui .fallback, .swagger-ui .filter .loading, .swagger-ui .gray, .swagger-ui .hover-black:focus, .swagger-ui .hover-black:hover, .swagger-ui .hover-dark-gray:focus, .swagger-ui .hover-dark-gray:hover, .swagger-ui .hover-gray:focus, .swagger-ui .hover-gray:hover, .swagger-ui .hover-light-silver:focus, .swagger-ui .hover-light-silver:hover, .swagger-ui .hover-mid-gray:focus, .swagger-ui .hover-mid-gray:hover, .swagger-ui .hover-near-black:focus, .swagger-ui .hover-near-black:hover, .swagger-ui .hover-silver:focus, .swagger-ui .hover-silver:hover, .swagger-ui .light-silver, .swagger-ui .markdown pre, .swagger-ui .mid-gray, .swagger-ui .model .property, .swagger-ui .model .property.primitive, .swagger-ui .model-title, .swagger-ui .near-black, .swagger-ui .parameter__extension, .swagger-ui .parameter__in, .swagger-ui .prop-format, .swagger-ui .renderedmarkdown pre, .swagger-ui .response-col_links .response-undocumented, .swagger-ui .response-col_status .response-undocumented, .swagger-ui .silver, .swagger-ui section.models h4, .swagger-ui section.models h5, .swagger-ui span.token-not-formatted, .swagger-ui span.token-string, .swagger-ui table.headers .header-example, .swagger-ui table.model tr.description, .swagger-ui table.model tr.extension { + color: #bfbfbf; + } + + .swagger-ui .hover-white:focus, .swagger-ui .hover-white:hover, .swagger-ui .info .title small pre, .swagger-ui .topbar a, .swagger-ui .white { + color: #fff; + } + + .swagger-ui .bg-black-10, .swagger-ui .hover-bg-black-10:focus, .swagger-ui .hover-bg-black-10:hover, .swagger-ui .stripe-dark:nth-child(2n + 1) { + background-color: rgba(0, 0, 0, .1); + } + + .swagger-ui .bg-white-10, .swagger-ui .hover-bg-white-10:focus, .swagger-ui .hover-bg-white-10:hover, .swagger-ui .stripe-light:nth-child(2n + 1) { + background-color: rgba(28, 28, 33, .1); + } + + .swagger-ui .bg-light-silver, .swagger-ui .hover-bg-light-silver:focus, .swagger-ui .hover-bg-light-silver:hover, .swagger-ui .striped--light-silver:nth-child(2n + 1) { + background-color: #6e6e6e; + } + + .swagger-ui .bg-moon-gray, .swagger-ui .hover-bg-moon-gray:focus, .swagger-ui .hover-bg-moon-gray:hover, .swagger-ui .striped--moon-gray:nth-child(2n + 1) { + background-color: #4d4d4d; + } + + .swagger-ui .bg-light-gray, .swagger-ui .hover-bg-light-gray:focus, .swagger-ui .hover-bg-light-gray:hover, .swagger-ui .striped--light-gray:nth-child(2n + 1) { + background-color: #2b2b2b; + } + + .swagger-ui .bg-near-white, .swagger-ui .hover-bg-near-white:focus, .swagger-ui .hover-bg-near-white:hover, .swagger-ui .striped--near-white:nth-child(2n + 1) { + background-color: #242424; + } + + .swagger-ui .opblock-tag:hover, .swagger-ui section.models h4:hover { + background: rgba(0, 0, 0, .02); + } + + .swagger-ui .checkbox p, .swagger-ui .dialog-ux .modal-ux-content h4, .swagger-ui .dialog-ux .modal-ux-content p, .swagger-ui .dialog-ux .modal-ux-header h3, .swagger-ui .errors-wrapper .errors h4, .swagger-ui .errors-wrapper hgroup h4, .swagger-ui .info .base-url, .swagger-ui .info .title, .swagger-ui .info h1, .swagger-ui .info h2, .swagger-ui .info h3, .swagger-ui .info h4, .swagger-ui .info h5, .swagger-ui .info li, .swagger-ui .info p, .swagger-ui .info table, .swagger-ui .loading-container .loading::after, .swagger-ui .model, .swagger-ui .opblock .opblock-section-header h4, .swagger-ui .opblock .opblock-section-header > label, .swagger-ui .opblock .opblock-summary-description, .swagger-ui .opblock .opblock-summary-operation-id, .swagger-ui .opblock .opblock-summary-path, .swagger-ui .opblock .opblock-summary-path__deprecated, .swagger-ui .opblock-description-wrapper, .swagger-ui .opblock-description-wrapper h4, .swagger-ui .opblock-description-wrapper p, .swagger-ui .opblock-external-docs-wrapper, .swagger-ui .opblock-external-docs-wrapper h4, .swagger-ui .opblock-external-docs-wrapper p, .swagger-ui .opblock-tag small, .swagger-ui .opblock-title_normal, .swagger-ui .opblock-title_normal h4, .swagger-ui .opblock-title_normal p, .swagger-ui .parameter__name, .swagger-ui .parameter__type, .swagger-ui .response-col_links, .swagger-ui .response-col_status, .swagger-ui .responses-inner h4, .swagger-ui .responses-inner h5, .swagger-ui .scheme-container .schemes > label, .swagger-ui .scopes h2, .swagger-ui .servers > label, .swagger-ui .tab li, .swagger-ui label, .swagger-ui select, .swagger-ui table.headers td { + color: #b5bac9; + } + + .swagger-ui .download-url-wrapper .failed, .swagger-ui .filter .failed, .swagger-ui .model-deprecated-warning, .swagger-ui .parameter__deprecated, .swagger-ui .parameter__name.required span, .swagger-ui table.model tr.property-row .star { + color: #e69999; + } + + .swagger-ui .opblock-body pre.microlight, .swagger-ui textarea.curl { + background: #41444e; + border-radius: 4px; + color: #fff; + } + + .swagger-ui .expand-methods svg, .swagger-ui .expand-methods:hover svg { + fill: #bfbfbf; + } + + .swagger-ui .auth-container, .swagger-ui .dialog-ux .modal-ux-header { + border-bottom: 1px solid #2e2e2e; + } + + .swagger-ui .topbar .download-url-wrapper .select-label select, .swagger-ui .topbar .download-url-wrapper input[type=text] { + border: 2px solid #63a040; + } + + .swagger-ui .info a, .swagger-ui .info a:hover, .swagger-ui .scopes h2 a { + color: #99bde6; + } + + /* Dark Scrollbar */ + ::-webkit-scrollbar { + width: 14px; + height: 14px; + } + + ::-webkit-scrollbar-button { + background-color: #3e4346 !important; + } + + ::-webkit-scrollbar-track { + background-color: #646464 !important; + } + + ::-webkit-scrollbar-track-piece { + background-color: #3e4346 !important; + } + + ::-webkit-scrollbar-thumb { + height: 50px; + background-color: #242424 !important; + border: 2px solid #3e4346 !important; + } + + ::-webkit-scrollbar-corner { + } + + ::-webkit-resizer { + } + + ::-webkit-scrollbar-button:vertical:start:decrement { + background: linear-gradient(130deg, #696969 40%, rgba(255, 0, 0, 0) 41%), linear-gradient(230deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(0deg, #696969 40%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button:vertical:end:increment { + background: linear-gradient(310deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(50deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(180deg, #696969 40%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button:horizontal:end:increment { + background: linear-gradient(210deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(330deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(90deg, #696969 30%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; + } + + ::-webkit-scrollbar-button:horizontal:start:decrement { + background: linear-gradient(30deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(150deg, #696969 40%, rgba(0, 0, 0, 0) 41%), linear-gradient(270deg, #696969 30%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; + } +} diff --git a/e-suite.API/nuget.config b/e-suite.API/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.API/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Automation.APITests/README.md b/e-suite.Automation.APITests/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Automation.APITests/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Automation.APITests/e-suite.Autimation.APITests.sln b/e-suite.Automation.APITests/e-suite.Autimation.APITests.sln new file mode 100644 index 0000000..bc89b2d --- /dev/null +++ b/e-suite.Automation.APITests/e-suite.Autimation.APITests.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Autimation.APITests", "e-suite.Autimation.APITests\e-suite.Autimation.APITests.csproj", "{18511718-57BF-4942-96E9-CEC195F13D79}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {18511718-57BF-4942-96E9-CEC195F13D79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18511718-57BF-4942-96E9-CEC195F13D79}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18511718-57BF-4942-96E9-CEC195F13D79}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18511718-57BF-4942-96E9-CEC195F13D79}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D54131F7-4014-494C-B0CC-310B230D5170} + EndGlobalSection +EndGlobal diff --git a/e-suite.Automation.APITests/e-suite.Autimation.APITests.sln.DotSettings.user b/e-suite.Automation.APITests/e-suite.Autimation.APITests.sln.DotSettings.user new file mode 100644 index 0000000..563edab --- /dev/null +++ b/e-suite.Automation.APITests/e-suite.Autimation.APITests.sln.DotSettings.user @@ -0,0 +1,6 @@ + + <SessionState ContinuousTestingMode="0" IsActive="True" Name="Authentication_Login_NoContentIncluded_DeniesAccess" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <TestAncestor> + <TestId>NUnit3x::18511718-57BF-4942-96E9-CEC195F13D79::net6.0::e_suite.Autimation.APITests.AuthenticationTests.Authentication_Login_NoContentIncluded_DeniesAccess</TestId> + </TestAncestor> +</SessionState> \ No newline at end of file diff --git a/e-suite.Automation.APITests/e-suite.Autimation.APITests.v3.ncrunchsolution.user b/e-suite.Automation.APITests/e-suite.Autimation.APITests.v3.ncrunchsolution.user new file mode 100644 index 0000000..b82f7a5 --- /dev/null +++ b/e-suite.Automation.APITests/e-suite.Autimation.APITests.v3.ncrunchsolution.user @@ -0,0 +1,5 @@ + + + Run all tests automatically [Global] + + \ No newline at end of file diff --git a/e-suite.Automation.UITests/.gitattributes b/e-suite.Automation.UITests/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Automation.UITests/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Automation.UITests/.gitignore b/e-suite.Automation.UITests/.gitignore new file mode 100644 index 0000000..f78d4b6 --- /dev/null +++ b/e-suite.Automation.UITests/.gitignore @@ -0,0 +1,204 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# Selenium compiled files +*.feature.cs + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Automation.UITests/DependencyConfig.cs b/e-suite.Automation.UITests/DependencyConfig.cs new file mode 100644 index 0000000..3d1ad8d --- /dev/null +++ b/e-suite.Automation.UITests/DependencyConfig.cs @@ -0,0 +1,30 @@ +using Autofac; +using ESuite.UI.E2E.Hooks; +using ESuite.UI.E2E.StepDefinitions; +using Reqnroll.Autofac; +using System.Linq; +using System.Reflection; + +namespace ESuite.UI.E2E +{ + public static class DependencyConfig + { + [ScenarioDependencies] + public static void ConfigureDependencies(ContainerBuilder builder) + { + var stepDefinitionTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => t.Name.EndsWith("StepDefinitions")); + + // Register all StepDefinition classes as themselves + foreach (var type in stepDefinitionTypes) + { + builder.RegisterType(type).AsSelf().InstancePerLifetimeScope(); + } + + // Register specific hooks or other necessary dependencies + builder.RegisterType().As().InstancePerLifetimeScope(); + + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E.sln b/e-suite.Automation.UITests/ESuite.UI.E2E.sln new file mode 100644 index 0000000..dc47860 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33815.320 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ESuite.UI.E2E", "ESuite.UI.E2E\ESuite.UI.E2E.csproj", "{99161135-3027-41E2-AC60-146D9BB59601}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Auto|Any CPU = Auto|Any CPU + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {99161135-3027-41E2-AC60-146D9BB59601}.Auto|Any CPU.ActiveCfg = Auto|Any CPU + {99161135-3027-41E2-AC60-146D9BB59601}.Auto|Any CPU.Build.0 = Auto|Any CPU + {99161135-3027-41E2-AC60-146D9BB59601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99161135-3027-41E2-AC60-146D9BB59601}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99161135-3027-41E2-AC60-146D9BB59601}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99161135-3027-41E2-AC60-146D9BB59601}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FF8254B9-EB42-426F-9E4F-7C6679313540} + EndGlobalSection +EndGlobal diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/BrowserContext.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/BrowserContext.cs new file mode 100644 index 0000000..782d908 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/BrowserContext.cs @@ -0,0 +1,27 @@ +using ESuite.UI.E2E.Helpers; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E +{ + [Binding] + public class BrowserContext + { + public static IWebDriver? driver { get; private set; } + + [BeforeScenario(Order = 1)] + public static void InitializeDriver() + { + driver = WebDriverHelper.GetWebDriver(); + } + public static void DeleteCookies() + { + driver!.Manage().Cookies.DeleteAllCookies(); + } + + [AfterTestRun] + public static void Dispose() + { + driver?.Quit(); + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/DependencyConfig.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/DependencyConfig.cs new file mode 100644 index 0000000..5c5b4c6 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/DependencyConfig.cs @@ -0,0 +1,35 @@ +using Autofac; +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Hooks; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using Reqnroll.Autofac; +using System.Reflection; + +namespace ESuite.UI.E2E +{ + public static class DependencyConfig + { + [ScenarioDependencies] + public static void ConfigureDependencies(ContainerBuilder builder) + { + var stepDefinitionTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => t.Name.EndsWith("StepDefinitions")); + + // Register all StepDefinition classes as themselves + foreach (var type in stepDefinitionTypes) + { + builder.RegisterType(type).AsSelf().InstancePerLifetimeScope(); + } + + // Register specific hooks or other necessary dependencies + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/ESuite.UI.E2E.csproj b/e-suite.Automation.UITests/ESuite.UI.E2E/ESuite.UI.E2E.csproj new file mode 100644 index 0000000..8ba70cf --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/ESuite.UI.E2E.csproj @@ -0,0 +1,57 @@ + + + + net9.0 + enable + enable + Debug;Release;Auto + + + + + + + + + + + Always + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/CustomFieldsManagement.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/CustomFieldsManagement.feature new file mode 100644 index 0000000..2522e1d --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/CustomFieldsManagement.feature @@ -0,0 +1,180 @@ +Feature: Custom Fields Management +As admin +I can create, update and delete custom fields + +@auth @createsequence @logout +Scenario: Creation and Update and Delete Custom Field Sequence and check audit logs + Given I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCFS | Sequence | | sequenceName | | + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + Given I create a new Sequence via API + | Name | + | NewName | + When I edit a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | EDITTestCFSequence | Sequence | | sequenceName | | + Then I check data on Custom Field page + | FieldType | + | Sequence | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I delete a CustomField + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @logout +Scenario: Creation and Update and Delete Custom Field Glossary and check audit logs + Given I create a Glossary + | Name | Add | + | TestGlossary | | + When I create a CustomField + | Name | FieldType | MaxEntries | Required | Glossary | + | TestCFGlossary | Glossary | 1 | true | | + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + And I check data on Custom Field page + | FieldType | + | Glossary | + When I create a Glossary + | Name | Add | + | NewTestGlossary | | + And I edit a CustomField + | Name | FieldType | MaxEntries | Required | Glossary | + | EDITTestCFGlossary | Glossary | 3 | false | | + Then I check data on Custom Field page + | FieldType | + | Glossary | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I delete a CustomField + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @logout +Scenario: Creation and Update and Delete Custom Field Form Template and check audit logs + Given I create a CustomField + | Name | FieldType | + | TestCFForm Template | Form Template | + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit a CustomField + | Name | FieldType | + | EDITTestCFForm Template | Form Template | + Then I check data on Custom Field page + | FieldType | + | Form Template | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I delete a CustomField + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @logout +Scenario: Creation and Update and Delete Custom Field Text and check audit logs + Given I create a CustomField + | Name | FieldType | DefaultValue | MultiLine | + | TestCFText | Text | Default Text | true | + Then I check data on Custom Field page + | FieldType | + | Text | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit a CustomField + | Name | FieldType | DefaultValue | MultiLine | + | EDITTestCFText | Text | Edited Default Text | false | + Then I check data on Custom Field page + | FieldType | + | Text | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I delete a CustomField + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @logout +Scenario: Creation and Update and Delete Custom Field Number and check audit logs + Given I create a CustomField + | Name | FieldType | DefaultValue | MinimumValue | MaximumValue | Step | Required | + | TestCFNumber | Number | 1 | 1 | 999 | 2 | true | + Then I check data on Custom Field page + | FieldType | + | Number | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit a CustomField + | Name | FieldType | DefaultValue | MinimumValue | MaximumValue | Step | Required | + | EDIT_TestCFNumber | Number | 2 | 2 | 777 | 3 | false | + Then I check data on Custom Field page + | FieldType | + | Number | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I delete a CustomField + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @deletecustomfield @logout +Scenario: Creation and Change Custom Field Type and check audit logs + Given I create a CustomField + | Name | FieldType | DefaultValue | MultiLine | + | TestCFText | Text | Default Text | true | + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit a CustomField + | Name | FieldType | + | EDITTestCFText | Form Template | + Then I check data on Custom Field page + | FieldType | + | Form Template | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + And I check Custom Field Text Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Purge | formNameFromScenarioContext | | + +@auth @logout +Scenario: Creation and Update and Delete Custom Field Domain and check audit logs + Given I create a CustomField + | Name | FieldType | MaxEntries | Required | + | TestCFDomain | Domain | 1 | true | + Then I check data on Custom Field page + | FieldType | + | Domain | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit a CustomField + | Name | FieldType | MaxEntries | Required | + | EDITTestCFDomain | Domain | 22 | false | + Then I check data on Custom Field page + | FieldType | + | Domain | + And I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I delete a CustomField + Then I check Custom Field Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/DomainCreation.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/DomainCreation.feature new file mode 100644 index 0000000..7bfeab5 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/DomainCreation.feature @@ -0,0 +1,80 @@ +Feature: Domain creation +As admin +I can create and edit domain + +@auth @createssoprovider @deletessoprovider @deletedomain @logout +Scenario Outline: Creating new domain and changing Mail Template 'Confirm Email Address' + Given I create a new domain + | Name | SSOProvider | + | | | + When I edit created domain + Then I change Mail Template + | TemplateName | Subject | Definition | + | Confirm Email Address | E2E e-mail confirmation | Confirmation | + When I edit created domain + And I check Mail Template changes +Examples: + | DomainName | SSOProvider | + | TestDomain | Google SSO | + | TestDomain | | + +@auth @createssoprovider @deletessoprovider @deletedomain @logout +Scenario Outline: Creating new domain and changing Mail Template 'Password reset' + Given I create a new domain + | Name | SSOProvider | + | | | + When I edit created domain + Then I change Mail Template + | TemplateName | Subject | Definition | + | Password Reset | E2E e-mail Password reset | Password reset | + When I edit created domain + And I check Mail Template changes +Examples: + | DomainName | SSOProvider | + | TestDomain | Google SSO | + | TestDomain | | + +@auth @createssoprovider @deletessoprovider @deletedomain @logout +Scenario Outline: Creating new domain and Security Role with custom permissions and User + Given I create a new domain + | Name | SSOProvider | + | | | + When I edit created domain + Then I add a new Security Role + | RoleName | + | QA Admin | + And I check new Security Role created + When I click on newly created Security Role + Then I choose Role Access permission options + | Allowed | Name | Group | Description | + | | Add User | | | + | | Edit User | | | + When I enter into Users tab + Then I add User to Security Role + | UserName | + | Test1 User | + And I check new Security Role created + When I click on newly created Security Role + And I enter into Users tab + Then I check if user is added to Security Role +Examples: + | DomainName | SSOProvider | + | TestDomain | Google SSO | + | TestDomain | | + +@auth @createssoprovider @createdomain @deletessoprovider @logout +Scenario: Creating new domain via api update and delete audit log + Then I check Client Domains Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | scenarioDataInstance | | + When I edit created domain + And I edit domains details + | Name | SSOProvider | + | EditTestDomainName | SSOProvider | + Then I check Client Domains Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | scenarioDataInstance | | + When I delete existing Domain + Then I check Client Domains Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | scenarioDataInstance | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/ErrorLogsVerification.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/ErrorLogsVerification.feature new file mode 100644 index 0000000..9667b67 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/ErrorLogsVerification.feature @@ -0,0 +1,8 @@ +Feature: ErrorLogsVerification +As admin +I can verify error logs + +@auth @logout +Scenario: Creating Exception via API call and Verifying in the Error Logs page + Given I create a new domain with insufficient info via API call + Then I verifying newly created exception on the Error Logs page diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/GlossaryObjects.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/GlossaryObjects.feature new file mode 100644 index 0000000..87bd1f9 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/GlossaryObjects.feature @@ -0,0 +1,81 @@ +Feature: Glossary Objects +As admin +I can manage Glossary and related objects + +@auth @logout +Scenario: Creation of Glossary with Sequence + Given I create a new Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | TestSequence | 1 | 1 | ID:[000000] Date:{DD} | Day | + When I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCF | Sequence | | sequenceName | | + And I create a Glossary + | Name | Add | + | TestGlossary | customField | + Then I create a Glossary Item + | Name | CustomField | + | TestGlossaryItem | customFieldNameFromScenarioContext | + +@auth @deleteform @logout +Scenario: Creation of Glossary with Form + Given I create a new Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | TestSequence | 1 | 1 | ID:[000000] Date:{DD} | Day | + When I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCF | Sequence | | sequenceName | | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestForm | true | 2 | 2 | customFieldNameFromScenarioContext | | 1 | 2 | + | | | | | | Field for E2E | 1 | 1 | + Then I check if version of FormTemplate version is correct + | Version | + | 1 | + And I check Forms Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | scenarioDataInstance | | + When I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCF-Form | Form Template | | | | + And I create a Glossary + | Name | Add | + | TestGlossary | form | + Then I check Glossaries Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | scenarioDataInstance | | + And I create a Glossary Item + | Name | CustomField | + | TestGlossaryItem | customFieldNameFromScenarioContext | + And I check Glossary Item Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | scenarioDataInstance | | + And I check Glossary Custom Field Value Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | scenarioDataInstance | | + +@auth @logout +Scenario: Editing Form and check of Audit log + Given I create a new Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | TestSequence3 | 1 | 1 | ID:[000000] Date:{DD} | Day | + When I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCF3 | Sequence | | sequenceName | | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | Version | RowNumber | ColumnNumber | + | TestForm3 | true | 2 | 2 | customFieldNameFromScenarioContext | | 1 | 1 | 2 | + | | | | | | Field for E2E | 1 | 1 | 1 | + And I edit a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | Version | RowNumber | ColumnNumber | + | | | 2 | | | - Edited text here! | 2 | 1 | 1 | + Then I check if version of FormTemplate was changed + | Version | + | 2 | + And I check Forms Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Update | scenarioDataInstance | | + When I delete existing Form Template + Then I check Form Template Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Delete | scenarioDataInstance | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/MailTemplateManagement.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/MailTemplateManagement.feature new file mode 100644 index 0000000..23614ad --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/MailTemplateManagement.feature @@ -0,0 +1,24 @@ +Feature: Mail Template Management +As admin +I can create and edit Mail Template + +@auth @createssoprovider @createdomain @deletessoprovider @deletedomain @logout +Scenario Outline: Create and update Mail Template auditlogs + When I edit created domain + Then I change Mail Template + | TemplateName | Subject | Definition | + | Password Reset | E2E e-mail Password reset | Password reset | + When I edit created domain + And I check Mail Template changes + Then I check Mail Template Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit created domain + Then I change Mail Template + | TemplateName | Subject | Definition | + | Password Reset | E2E e-mail Editing name | Edited Confirmation | + Then I check Mail Template Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I edit created domain + And I check Mail Template changes \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/OrganisationCreation.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/OrganisationCreation.feature new file mode 100644 index 0000000..9e43cc2 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/OrganisationCreation.feature @@ -0,0 +1,43 @@ +Feature: Organisation and site creation +As admin +I can create and edit organisation + +@auth @deleteorganisation @logout +Scenario: Creating new organisation with site + Given I create a new organisation + | Name | Address | Status | + | TestOrg | Somewhere str | Active | + Then I add a new site + | Name | Address | Status | + | TestSite | Site str | Pending | + +@auth @createorganisation_site @logout +Scenario: Creating new organisation with site via api and check audit log + Then I check Organisation Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + Then I check Site Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I delete existing Organisation + Then I check Organisation Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + Then I check Site Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @createorganisation_site @deleteorganisation @logout +Scenario: Creating new organisation with site and update organisation and site + When I edit existing Organisation + | Name | Address | Status | + | EditedTestOrg | Edited Somewhere str | Pending | + Then I check Organisation Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | + When I edit existing Site + | Name | Address | Status | + | EditedTestSite | Edited Somewhere str | Blocked | + Then I check Site Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | formNameFromScenarioContext | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/PasswordResetForgot.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/PasswordResetForgot.feature new file mode 100644 index 0000000..24ec4cb --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/PasswordResetForgot.feature @@ -0,0 +1,48 @@ +Feature: Password Reset Forgot and Validation + In order to reset my password + As a user + I want to be able to request a password reset link and validate the email + +@createdomain @deleteuserapi @deletedomainapi @logout +Scenario Outline: Validation password reset from acount profile check + Given I create a new user via API + When I click on the Link in the sent email + Then I enter a new password and confirm it + | Password | + | Pa55W()rD | + And I successfully login with new credentials and I do not see the login page anymore + When I attempt to change the Password on the My Account page with: + Then The password validation should check the following criteria + | validationText | passed | + | At least 12 characters | | + | At least 1 uppercase letter | | + | At least 1 lowercase letter | | + | At least 1 number | | + | At least 1 symbol | | +Examples: + | NewPassword | LengthPassed | UppercasePassed | LowercasePassed | NumberPassed | SpecialCharacterPassed | + | Password12! | false | true | true | true | true | + | test@1~`!@#$ | true | false | true | true | true | + | TEST@1~`!@#$ | true | true | false | true | true | + | Test@q~`!@#$ | true | true | true | false | true | + | Abcd1234pol1 | true | true | true | true | false | + | Password123! | true | true | true | true | true | + +@auth @logout +Scenario Outline: Validation create new password check + When I attempt to create the Password on registration page with: + Then The password validation should check the following criteria + | validationText | passed | + | At least 12 characters | | + | At least 1 uppercase letter | | + | At least 1 lowercase letter | | + | At least 1 number | | + | At least 1 symbol | | +Examples: + | NewPassword | LengthPassed | UppercasePassed | LowercasePassed | NumberPassed | SpecialCharacterPassed | + | Password12! | false | true | true | true | true | + | test@1~`!@#$ | true | false | true | true | true | + | TEST@1~`!@#$ | true | true | false | true | true | + | Test@q~`!@#$ | true | true | true | false | true | + | Abcd1234pol1 | true | true | true | true | false | + | Password123! | true | true | true | true | true | diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SecurityRoleManagement.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SecurityRoleManagement.feature new file mode 100644 index 0000000..3c84d6c --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SecurityRoleManagement.feature @@ -0,0 +1,47 @@ +Feature: Domain Role Management +As admin +I can create and edit domain security roles + +@auth @createuser @createdomain @deleteuser @deletedomain @logout +Scenario: Creating and update and delete Security Role audit logs check + Given I add a new Security Role via API + And I edit created domain + Then I check Role Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I edit created domain + Then I check new Security Role created + When I click on newly created Security Role + Then I choose Role Access permission options + | Allowed | Name | Group | Description | + | | Add User | | | + | | Edit User | | | + Then I check Role Access Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I delete added Security Role + Then I check Role Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | formNameFromScenarioContext | | + +@auth @createuser @createdomain @deleteuser @deletedomain @logout +Scenario: Creating and update and delete User Role audit logs check + Given I add a new Security Role via API + And I edit created domain + Then I check new Security Role created + When I click on newly created Security Role + When I enter into Users tab + Then I add User to Security Role + | UserName | + | UserName | + Then I check new Security Role created + When I click on newly created Security Role + When I enter into Users tab + Then I check if user is added to Security Role + Then I check UserRoles Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | formNameFromScenarioContext | | + When I delete added User from Security Role + Then I check UserRoles Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Purge | formNameFromScenarioContext | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SequenceManagement.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SequenceManagement.feature new file mode 100644 index 0000000..c795c86 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SequenceManagement.feature @@ -0,0 +1,35 @@ +Feature: Sequence Management +As admin +I can create and edit and delete Sequence + + +@auth @logout +Scenario: Create Sequence and Update Sequence and Deleting Sequence and check of Audit log + Given I create a new Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | TestSequence123 | 1 | 1 | ID:[000000] | Continuous | + Then I check Sequence Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | scenarioDataInstance | | + When I update existing Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | EDITED_Day_TestSequence123 | 2 | 3 | ID:[0000] Day:{DD} | Day | + Then I check Sequence Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Update | scenarioDataInstance | | + When I update existing Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | EDITED_Month_TestSequence123 | 12 | 13 | ID:[0000] Month:{MM} | Month | + Then I check Sequence Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Update | scenarioDataInstance | | + When I update existing Sequence + | Name | Seed | Increment | Pattern | RolloverType | + | EDITED_Year_TestSequence123 | 22 | 23 | ID:[0000] Year:{YYYY} | Year | + Then I check Sequence Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Update | scenarioDataInstance | | + When I delete a sequence + Then I check Sequence Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Delete | scenarioDataInstance | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SpecificationManager.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SpecificationManager.feature new file mode 100644 index 0000000..b18b6ef --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SpecificationManager.feature @@ -0,0 +1,344 @@ +Feature: SpecificationManager +As admin +I can create Specifications + +@auth @createorganisation_site @deleteorganisation @deleteform @logout +Scenario: Creating and Updating new Specification and then check Audit logs + Given I create a Glossary + | Name | + | TestColoursGlossary | + And I create a Glossary Item + | Name | + | TestBlackGlossaryItemDifferent | + | TestBlackGlossaryItem | + And I create a CustomField + | Name | FieldType | Glossary | MaxEntries | + | TestColoursCF | Glossary | TestBlackGlossaryItem | 1 | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate | true | 2 | 1 | Glossary | | 1 | 2 | + | | | | | | Glossary | 1 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm | + Then I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | defaultGlossary | + And I check Specification Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | formNameFromScenarioContext | | + And I check Form Field Instance Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Create | formFieldInstanceNameFromScenarioContext | | + And I edit a Specification + | Name | SpecificationItems | ItemValue | + | EditedTestCploursSpecification | Glossary | TestBlackGlossaryItemDifferent | + And I check Specification Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Update | formNameFromScenarioContext | | + + And I check Form Field Instance Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Update | formFieldInstanceNameFromScenarioContext | | + + +@auth @createdomain @createorganisation_site @createsequence @deleteorganisation @deletedomain @deleteform @logout +Scenario: Creating and deleting new Specification contains all custom fields + Given I create a Glossary + | Name | + | TestColoursGlossary | + And I create a Glossary Item + | Name | + | TestBlackGlossaryItem | + And I create a CustomField + | Name | FieldType | Glossary | MaxEntries | + | TestColoursCF | Glossary | TestBlackGlossaryItem | 1 | + And I create a CustomField + | Name | FieldType | MaxEntries | Required | MaxEntries | + | TestCFDomain | Domain | 1 | true | 1 | + And I create a CustomField + | Name | FieldType | DefaultValue | MultiLine | + | TestCFText | Text | Default Text | true | + And I create a CustomField + | Name | FieldType | DefaultValue | MinimumValue | MaximumValue | Step | Required | + | TestCFNumber | Number | 1 | 1 | 999 | 2 | true | + And I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCFS | Sequence | | sequenceName | | + And I create a CustomField + | Name | FieldType | + | TestCFForm Template | Form Template | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | ChildFormName | + | Form to use in specification | true | 2 | 2 | Text | | 1 | 2 | contextName | + | | | | | | Field for E2E | 1 | 1 | | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate | true | 2 | 6 | Glossary | | 1 | 2 | + | | | | | Domain | | 2 | 2 | + | | | | | Sequence | | 3 | 2 | + | | | | | Text | | 4 | 2 | + | | | | | Number | | 5 | 2 | + | | | | | Form Template | | 6 | 2 | + | | | | | | Glossary | 1 | 1 | + | | | | | | Domain | 2 | 1 | + | | | | | | Sequence | 3 | 1 | + | | | | | | Text | 4 | 1 | + | | | | | | Number | 5 | 1 | + | | | | | | Form Template | 6 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm | + Then I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | defaultGlossary | + | | | | | Domain | default | + | | | | | Sequence | Sequnce linked | + | | | | | Text | Free text field or description | + | | | | | Number | 21 | + | | | | | Form Template | defaultTemplate | + And I check data on Specification + | SpecificationItems | ItemValue | + | Glossary | dataFromScenarioContext | + | Domain | dataFromScenarioContext | + | Sequence | dataFromScenarioContext | + | Text | dataFromScenarioContext | + | Number | 21 | + | Form Template | dataFromScenarioContext | + And new Specification is present on the list + When I delete existing Specification + Then new Specification is not present on the list + And I check Specification Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Delete | formNameFromScenarioContext | | + +#Bug 72982 uncomment after fix +@auth @createdomain @createsequence @createorganisation_site @deletedomain @deleteorganisation @deleteform @logout +Scenario: Creating a new Specification contains custom fields with default or null values + Given I create a Glossary + | Name | + | TestColoursGlossary | + And I create a Glossary Item + | Name | + | TestBlackGlossaryItem | + And I create a CustomField + | Name | FieldType | Glossary | MaxEntries | + | TestColoursCF | Glossary | TestBlackGlossaryItem | 1 | + And I create a CustomField + | Name | FieldType | MaxEntries | Required | MaxEntries | + | TestCFDomain | Domain | 1 | false | 1 | + And I create a CustomField + | Name | FieldType | DefaultValue | MultiLine | + | TestCFText | Text | | false | + #And I create a CustomField + # | Name | FieldType | DefaultValue | MinimumValue | MaximumValue | Step | Required | + # | TestCFNumber | Number | 1 | 1 | 999 | 2 | true | + And I create a CustomField + | Name | FieldType | DefaultValue | Sequence | Glossary | + | TestCFS | Sequence | | sequenceName | | + And I create a CustomField + | Name | FieldType | + | TestCFForm Template | Form Template | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | ChildFormName | + | Form to use in specification | true | 2 | 2 | Text | | 1 | 2 | contextName | + | | | | | | Field for E2E | 1 | 1 | | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate | true | 2 | 6 | Glossary | | 1 | 2 | + | | | | | Domain | | 2 | 2 | + | | | | | Sequence | | 3 | 2 | + | | | | | Text | | 4 | 2 | + | | | | | Form Template | | 6 | 2 | + | | | | | | Glossary | 1 | 1 | + | | | | | | Domain | 2 | 1 | + | | | | | | Sequence | 3 | 1 | + | | | | | | Text | 4 | 1 | + | | | | | | Form Template | 6 | 1 | +# | | | | | Number | | 5 | 2 | +# | | | | | | Number | 5 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm | + Then I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | | + | | | | | Domain | | + | | | | | Sequence | Sequnce linked | + | | | | | Text | | + | | | | | Form Template | defaultTemplate | +# | | | | | Number | | + And I check data on Specification + | SpecificationItems | ItemValue | + | Glossary | | + | Domain | | + | Sequence | dataFromScenarioContext | + | Text | | + | Form Template | dataFromScenarioContext | +# | Number | | + +@auth @createorganisation_site @deleteorganisation @deleteform @logout +Scenario: Creating and deleting new Specification contains Gloassary custom field with empty default value and field is required + Given I create a Glossary + | Name | + | TestColoursGlossary | + And I create a Glossary Item + | Name | + | TestBlackGlossaryItem | + And I create a CustomField + | Name | FieldType | Glossary | MaxEntries | Required | + | TestColoursCF | Glossary | TestBlackGlossaryItem | | true | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate1 | true | 2 | 1 | Glossary | | 1 | 2 | + | | | | | | Glossary | 1 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm1 | + And I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification2 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | | + Then Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + When I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification3 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | defaultGlossary | + Then new Specification is present on the list + +@auth @createorganisation_site @createdomain @deleteorganisation @deleteform @logout +Scenario: Creating and deleting new Specification contains Form Template custom field with empty default value and field is required + Given I create a CustomField + | Name | FieldType | DefaultValue | MultiLine | + | TestCFText | Text | | false | + And I create a CustomField + | Name | FieldType | + | TestCFForm Template | Form Template | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | ChildFormName | + | Form to use in specification | true | 2 | 2 | Text | | 1 | 2 | contextName | + | | | | | | Field for E2E | 1 | 1 | | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate1 | true | 2 | 1 | Form Template | | 1 | 2 | + | | | | | | Form Template | 1 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm1 | + And I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification2 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Form Template | | + Then Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + When I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification3 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Form Template | defaultTemplate | + Then new Specification is present on the list + +@auth @createorganisation_site @createdomain @deleteorganisation @deletedomain @deleteform @logout +Scenario Outline: Creating a new Specification with custom field with empty default value and field is required + Given I create a CustomField + | Name | FieldType | MaxEntries | Required | DefaultValue | MinimumValue | MaximumValue | Step | + | TestCFDomain | | 1 | true | | 1 | 999 | 2 | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate1 | true | 2 | 1 | | | 1 | 2 | + | | | | | | | 1 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm1 | + And I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification2 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | | | + Then Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + When I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification3 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | | | + Then new Specification is present on the list +Examples: + | CustomField | ItemValue | + | Domain | default | + | Number | 21 | + +@auth @createorganisation_site @deleteorganisation @deletedomain @deleteform @logout +Scenario: Creating a new Specification contains Domain custom field MULTISELECT with empty default value and field is required + Given I create a new domain via API + | Name | + | DomainTest1 | + | DomainTest2 | + | DomainTest3 | + And I create a CustomField + | Name | FieldType | MaxEntries | Required | + | TestCFDomain | Domain | 2 | true | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate1 | true | 2 | 1 | Domain | | 1 | 2 | + | | | | | | Domain | 1 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm1 | + And I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification2 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Domain | | + Then Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + And new Specification is not present on the list + When I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | MultiselectField | NumberOfItems | + | TestColoursSpecification3 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Domain | default | true | 3 | + Then Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + And new Specification is not present on the list + When I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | MultiselectField | NumberOfItems | + | TestColoursSpecification3 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Domain | default | true | 2 | + Then new Specification is present on the list + +@auth @createorganisation_site @deleteorganisation @deleteform @logout +Scenario: Creating a new Specification contains Gloassary custom field MULTISELECT with empty default value and field is required + Given I create a Glossary + | Name | + | TestColoursGlossary | + And I create a Glossary Item + | Name | + | TestBlackGlossaryItem1 | + | TestBlackGlossaryItem2 | + | TestBlackGlossaryItem3 | + And I create a CustomField + | Name | FieldType | Glossary | MaxEntries | Required | + | TestColoursCF | Glossary | TestBlackGlossaryItem | 2 | true | + And I create a FormTemplate + | Name | NeedTable | TotalNumberOfColumns | TotalNumberOfRows | CustomFields | Text | RowNumber | ColumnNumber | + | TestColoursFormTemplate1 | true | 2 | 1 | Glossary | | 1 | 2 | + | | | | | | Glossary | 1 | 1 | + When I added a Form Template into the Print Specifications + | Name | + | TestPrintSpecificationsForm1 | + And I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | + | TestColoursSpecification2 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | | + Then Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + And I can not create a Specification with required fields and empty value + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | MultiselectField | NumberOfItems | + | TestColoursSpecification2 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | defaultGlossary | true | 3 | + And Error toast message is present + | Message | + | Request failed with status code 400 | + | Failed to save form instance | + When I create a Specification + | Name | OrganisationName | SiteName | PrintSpecification | SpecificationItems | ItemValue | MultiselectField | NumberOfItems | + | TestColoursSpecification3 | TestColoursOrg | TestColoursSite | TestPrintSpecificationsForm | Glossary | defaultGlossary | true | 2 | + Then new Specification is present on the list \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SsoManager.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SsoManager.feature new file mode 100644 index 0000000..d57ef31 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/SsoManager.feature @@ -0,0 +1,35 @@ +Feature: SSO Manager management +As admin +I can create, edit and delete SSO Provider + +@auth @deletessoprovider @logout +Scenario: Creating and editing new SSO Provider + Given I create a new SSO Provider + | Name | ClientID | ClientSecret | ValidIssuer | AuthorisationEndpoint | TokenEndpoint | IsPublic | + | TestSssoProvider | 778899937320-phjl4hpacmeele7k92650u5q73n66cqe.apps.googleusercontent.com | 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 | https://accounts.google.com | https://accounts.google.com/o/oauth2/auth | https://oauth2.googleapis.com/token | true | + Then new SSO Provider is present on the list + When I edit existing SSO Provider + | Name | ClientID | ClientSecret | ValidIssuer | AuthorisationEndpoint | TokenEndpoint | IsPublic | + | EDITED_TestSssoProvider | EDITED-phjl4hpacmeele7k92650u5q73n66cqe.apps.googleusercontent.com | EDITED-LtmAS3XnPIQ4ok3y-3CpWCN5w5X7 | https://accounts.google.com/EDITED | https://accounts.google.com/o/oauth2/auth/EDITED | https://oauth2.googleapis.com/token/EDITED | false | + Then I check edited data on SSO Provider page + And I check Sso Manager Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | scenarioDataInstance | | + +@auth @logout +Scenario: Creating and deleting new SSO Provider + Given I create a new SSO Provider + | Name | ClientID | ClientSecret | ValidIssuer | AuthorisationEndpoint | TokenEndpoint | IsPublic | + | TestSssoProvider | 778899937320-phjl4hpacmeele7k92650u5q73n66cqe.apps.googleusercontent.com | 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 | https://accounts.google.com | https://accounts.google.com/o/oauth2/auth | https://oauth2.googleapis.com/token | false | + Then new SSO Provider is present on the list + When I delete existing SSO Provider + Then new SSO Provider is not present on the list + And I check Sso Manager Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | | Delete | scenarioDataInstance | | + +@auth @createssoprovider @deletessoprovider @logout +Scenario: Creating a new SSO Provider through api and check audit logs + Then I check Sso Manager Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | scenarioDataInstance | | \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Features/UserCreation.feature b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/UserCreation.feature new file mode 100644 index 0000000..79830dd --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Features/UserCreation.feature @@ -0,0 +1,88 @@ +Feature: User functionality +I as admin +Will create a new user + +@auth @deleteuser @logout +Scenario: Creating and editing New user with Sun-Strategy domain + Given I create a new user + | Mail | FirstName | MiddleNames | LastName | Domain | + | tww44@inbox.testmail.app | Wolfgang | Amadeus | Mozart | Sun-Strategy | + And I logout + When I click on the Link in the sent email + Then I enter a new password and confirm it + | Password | + | Pa55W()rD | + And I successfully login with new credentials and I do not see the login page anymore + When I edit an existing user + | EditedFirstName | EditedMiddleNames | EditedLastName | Password | + | Test QA Edit | Middle QA Edit | User-1 QA Edit | Pa55W()rD12345 | + And I logout + Then I successfully login with new credentials and I do not see the login page anymore + And I logout + When I login as Admin + Then I check edited data on edit user page + And I check Users Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | scenarioDataInstance | | + +@auth @deleteuser @logout +Scenario: Creating and editing New user with Sun-Strategy domain 2FA + Given I create a new user + | Mail | FirstName | MiddleNames | LastName | Domain | + | tww44@inbox.testmail.app | Wolfgang | Amadeus | Mozart | Sun-Strategy | + And I logout + When I click on the Link in the sent email + Then I enter a new password and confirm it and add 2FA + | Password | MFA | + | Pa55W()rD | true | + And I successfully login with new credentials and 2FA + When I edit an existing user + | EditedFirstName | EditedMiddleNames | EditedLastName | MFA | + | Test QA Edit | Middle QA Edit | User-1 QA Edit | false | + Then I logout + And I successfully login with new credentials and I do not see the login page anymore + And I logout + When I login as Admin + Then I check edited data on edit user page + And I check Users Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Update | scenarioDataInstance | | + +@auth @createuser @logout +Scenario: Creating a new user by API and delete user and check audit log + Then I check Users Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Create | scenarioDataInstance | | + When I delete existing user + Then I check Users Audit logs + | Timing | UserName | Comment | EntityDisplayName | Type | DisplayName | Changes | + | | | | scenarioDataInstance | Delete | scenarioDataInstance | | + +@createdomain @deleteuserapi @deletedomain @logout +Scenario: Admin user can't delete himself + Given I create a new user via API + When I click on the Link in the sent email + Then I enter a new password and confirm it + | Password | + | Pa55W()rD | + And I assign Admin role to the user + And I successfully login with new credentials and I do not see the login page anymore + When I try to delete existing user + Then I can't delete myself + +#@auth @logout +#Scenario: Creating a new user by API and Reset Password +# Given I create a new user through an API call +# | Mail | FirstName | MiddleNames | LastName | Domain | +# | apiuser@inbox.testmail.app | Test | API | User | Sun-Strategy | +# When I click on the Link in the sent email +# Then I enter a new password and confirm it +# | Password | FormMessage | +# | Pa55W()rD | Success, your e-mail is confirmed. You can now log in. | +# When I logout +# Then I am resetting the password for the newly created user +# When I click on the Link in the reset password email +# Then I enter a new password and save it +# | Password | +# | Reset@123456 | +# Then I successfully login with new credentials and I do not see the login page anymore \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/GlobalSuppressions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/GlobalSuppressions.cs new file mode 100644 index 0000000..2937464 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/APIHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/APIHelper.cs new file mode 100644 index 0000000..bd5bd58 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/APIHelper.cs @@ -0,0 +1,489 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net.Http.Headers; +using System.Text; + +namespace ESuite.UI.E2E.Helpers +{ + public class APIHelper + { + private readonly HttpClient httpClient; + private readonly ConfigHelper configHelper; + private readonly ScenarioContext _scenarioContext; + + public APIHelper(ScenarioContext scenarioContext) + { + this.httpClient = new HttpClient(); + configHelper = new ConfigHelper(); + _scenarioContext = scenarioContext; + } + + public async Task SendGetRequest(string url) + { + try + { + HttpResponseMessage response = await httpClient.GetAsync(url); + + return await response.Content.ReadAsStringAsync(); + } + catch (Exception ex) + { + throw new Exception($"Error sending GET request: {ex.Message}"); + } + } + + public async Task SendPostRequest(string url, string requestBody) + { + try + { + StringContent content = new(requestBody, Encoding.UTF8, "application/json"); + + return await httpClient.PostAsync(url, content); + } + catch (Exception ex) + { + throw new Exception($"Error sending POST request: {ex.Message}"); + } + } + + private string _authToken { get; set; } = string.Empty; + + public void ClearAuthToken() + { + _authToken = string.Empty; + } + + public async Task GetAuthToken() + { + if (!string.IsNullOrWhiteSpace(_authToken)) + { + return _authToken; + } + + var url = $"{configHelper.APIUrl}/api/Authentication/login"; + + string requestBody = $@" + {{ + ""email"": ""{configHelper.AdminName}"", + ""password"": ""{configHelper.AdminPassword}"", + ""securityCode"": """", + ""requestTfaRemoval"": false + }}"; + + try + { + HttpResponseMessage response = await SendPostRequest(url, requestBody); + + if (response.IsSuccessStatusCode) + { + var responseContent = await response.Content.ReadAsStringAsync(); + _authToken = GetFieldValueFromJSONResponse("token", responseContent); + return _authToken; + } + else + { + throw new Exception("GetAuthToken Response is: " + response.StatusCode); + } + } + catch (Exception ex) + { + throw new Exception($"Error getting authentication token: {ex.Message}"); + } + } + + public async Task SendAuthenticatedRequest(string url, string token, string requestType = "GET") + { + try + { + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + HttpResponseMessage response; + + switch (requestType) + { + case "GET": response = await httpClient.GetAsync(url); break; + case "POST": + response = await httpClient.PostAsync(url, null); + if (response.IsSuccessStatusCode) + { + Console.WriteLine("Response content: " + await response.Content.ReadAsStringAsync()); + } + else + { + var body = await response.Content.ReadAsStringAsync(); + throw new Exception("Response status code from POST request: " + response.StatusCode + body); + } + break; + default: throw new Exception("Unknown request type"); + } + return await response.Content.ReadAsStringAsync(); + } + catch (Exception ex) + { + throw new Exception($"Error sending authenticated POST request: {ex.Message}"); + } + finally + { + httpClient.DefaultRequestHeaders.Authorization = null; + } + } + + public async Task SendAuthenticatedRequest(string url, string token, T requestBody = default!, string requestType = "GET") + { + try + { + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + HttpResponseMessage response; + + switch (requestType) + { + case "GET": response = await httpClient.GetAsync(url); break; + case "POST": + var postPayload = System.Text.Json.JsonSerializer.Serialize(requestBody); + StringContent postContent = new(postPayload!, Encoding.UTF8, "application/json"); + response = await httpClient.PostAsync(url, postContent); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + break; + case "DELETE": + var deletePayload = System.Text.Json.JsonSerializer.Serialize(requestBody); + var deleteContent = new StringContent(deletePayload, Encoding.UTF8, "application/json"); + + var request = new HttpRequestMessage + { + Method = HttpMethod.Delete, + RequestUri = new Uri(url), + Content = deleteContent + }; + + response = await httpClient.SendAsync(request); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + break; + default: throw new Exception("Unknown request type"); + } + return response; + + } + catch (Exception ex) + { + throw new Exception($"Error sending authenticated POST request: {ex.Message}"); + } + finally + { + httpClient.DefaultRequestHeaders.Authorization = null; + } + } + + public static string GetFieldValueFromJSONResponse(string field, dynamic jsonString) + { + try + { + dynamic json = JsonConvert.DeserializeObject(jsonString); + + return json[field]; ; + } + catch (Exception) + { + throw new Exception( + $"Error appears in process of getting field '{field}' data from JSON string: {jsonString}" + ); + } + } + + public async Task GetDomains(string url) + { + string token = await GetAuthToken(); + UriBuilder domainsUriBuilder = new($"{url}/api/Domain/domains"); + var query = System.Web.HttpUtility.ParseQueryString(domainsUriBuilder.Query); + query["SortAscending"] = "false"; + query["SortKey"] = "id"; + domainsUriBuilder.Query = query.ToString(); + string domainsUrl = domainsUriBuilder.ToString(); + string getDomainsResponse = await SendAuthenticatedRequest(domainsUrl, token); + + if (string.IsNullOrEmpty(getDomainsResponse)) + { + throw new Exception("Could not get response for getting all domains."); + } + + JObject getDomainsJson = JObject.Parse(getDomainsResponse); + + return getDomainsJson; + } + + public async Task GetUsers(string url) + { + string token = await GetAuthToken(); + + UriBuilder usersUriBuilder = new($"{url}/api/User/users"); + var query = System.Web.HttpUtility.ParseQueryString(usersUriBuilder.Query); + query["SortKey"] = "created"; + query["SortAscending"] = "false"; + + usersUriBuilder.Query = query.ToString(); + + string usersUrl = usersUriBuilder.ToString(); + string getUsersResponse = await SendAuthenticatedRequest(usersUrl, token); + + if (string.IsNullOrEmpty(getUsersResponse)) + { + throw new Exception("Could not get response for getting all Users."); + } + var settings = new JsonSerializerSettings + { + DateParseHandling = DateParseHandling.None, // Prevent automatic DateTime parsing + DateFormatHandling = DateFormatHandling.IsoDateFormat + }; + JObject getUsers = JsonConvert.DeserializeObject(getUsersResponse, settings)!; + return getUsers; + } + public async Task GetOrganisations(string url) + { + string token = await GetAuthToken(); + + UriBuilder usersUriBuilder = new($"{url}/api/Organisations/organisations"); + var query = System.Web.HttpUtility.ParseQueryString(usersUriBuilder.Query); + query["SortAscending"] = "false"; + query["SortKey"] = "id"; + usersUriBuilder.Query = query.ToString(); + + string usersUrl = usersUriBuilder.ToString(); + string getUsersResponse = await SendAuthenticatedRequest(usersUrl, token); + + if (string.IsNullOrEmpty(getUsersResponse)) + { + throw new Exception("Could not get response for getting all Organisations."); + } + + JObject getUsers = JsonConvert.DeserializeObject(getUsersResponse)!; + return getUsers; + } + + public async Task GetRoles(string url) + { + + string token = await GetAuthToken(); + UriBuilder rolesUriBuilder = new($"{url}/api/Role/roles"); + var query = System.Web.HttpUtility.ParseQueryString(rolesUriBuilder.Query); + query["SortAscending"] = "false"; + query["SortKey"] = "id"; + rolesUriBuilder.Query = query.ToString(); + string rolesUrl = rolesUriBuilder.ToString(); + string getRolesResponse = await SendAuthenticatedRequest(rolesUrl, token); + + if (string.IsNullOrEmpty(getRolesResponse)) + { + throw new Exception("Could not get response for getting all domains."); + } + + JObject getDomainsJson = JObject.Parse(getRolesResponse); + + return getDomainsJson; + } + + public async Task CreateNewUser(string url, string firstName, string middleName, string lastName, string email, int domainId) + { + var requestBody = new UserRegistration + { + FirstName = firstName, + MiddleNames = middleName, + LastName = lastName, + Email = email, + DomainId = new eSuite.Core.Miscellaneous.GeneralIdRef + { + Id = domainId + } + }; + + string token = await GetAuthToken(); + UriBuilder usersUriBuilder = new($"{url}/api/User/user"); + string usersUrl = usersUriBuilder.ToString(); + await SendAuthenticatedRequest(usersUrl, token, requestBody, "POST"); + } + + public async Task CreateNewSSOProvider(string url, string name, string clientId, string clientSecret, string validIssuer, string authorizationEndpoint, string tokenEndpoint, bool isPublic, Guid guid) + { + var requestBody = new CreateSsoProvider() + { + Name = name, + ClientId = clientId, + ClientSecret = clientSecret, + ValidIssuer = validIssuer, + AuthorizationEndpoint = authorizationEndpoint, + TokenEndpoint = tokenEndpoint, + IsPublic = isPublic, + Guid = guid + }; + + string token = await GetAuthToken(); + UriBuilder ssoProviderUriBuilder = new($"{url}/api/SsoManager/ssoProvider"); + string ssoProviderUrl = ssoProviderUriBuilder.ToString(); + await SendAuthenticatedRequest(ssoProviderUrl, token, requestBody, "POST"); + } + + public async Task CreateNewOrganisation(string url, Guid guid, string name, string address, OrganisationStatus status) + { + var requestBody = new CreateOrganisation() + { + Guid = guid, + Name = name, + Address = address, + Status = status + }; + + string token = await GetAuthToken(); + UriBuilder organisationUriBuilder = new($"{url}/api/Organisations/organisation"); + string siteUrl = organisationUriBuilder.ToString(); + HttpResponseMessage response = await SendAuthenticatedRequest(siteUrl, token, requestBody, "POST"); + return response; + } + + public async Task CreateNewSite(string url, Guid guid, string name, string address, OrganisationStatus status, int organisationId) + { + var requestBody = new CreateSite() + { + Name = name, + Address = address, + Status = status, + OrganisationId = new eSuite.Core.Miscellaneous.GeneralIdRef + { + Id = organisationId + }, + Guid = guid + }; + + string token = await GetAuthToken(); + UriBuilder siteUriBuilder = new($"{url}/api/Site/site"); + string siteUrl = siteUriBuilder.ToString(); + await SendAuthenticatedRequest(siteUrl, token, requestBody, "POST"); + } + + public async Task CreateNewDomain(string url, Guid guid, string name, string sunriseHostName, string sunriseAppId, string sunriseCategoryId, int? sigmaId) + { + var requestBody = new CreateDomain() + { + Guid = guid, + Name = name, + SunriseHostName = sunriseHostName, + SunriseAppId = sunriseAppId, + SunriseCategoryId = sunriseCategoryId, + SigmaId = sigmaId + }; + + string token = await GetAuthToken(); + UriBuilder domainUriBuilder = new($"{url}/api/Domain/domain"); + string siteUrl = domainUriBuilder.ToString(); + HttpResponseMessage response = await SendAuthenticatedRequest(siteUrl, token, requestBody, "POST"); + return response; + } + + public async Task CreateNewRole(string url, string name, Guid guid, bool isSuperUser, bool isAdministrator, int domainId) + { + var requestBody = new CreateRole + { + Name = name, + Guid = guid, + IsSuperUser = isSuperUser, + IsAdministrator = isAdministrator, + DomainId = new eSuite.Core.Miscellaneous.GeneralIdRef + { + Id = domainId + } + }; + + string token = await GetAuthToken(); + UriBuilder roleUriBuilder = new($"{url}/api/Role/role"); + string roleUrl = roleUriBuilder.ToString(); + await SendAuthenticatedRequest(roleUrl, token, requestBody, "POST"); + } + + public async Task CreateNewSequence(string url, string name, int seed, int increment, string pattern, Rollover rollOver, Guid guid) + { + var requestBody = new Sequence + { + Name = name, + Seed = seed, + Increment = increment, + Pattern = pattern, + RolloverType = rollOver, + GeneralIdRef = new eSuite.Core.Miscellaneous.GeneralIdRef() + { + Guid = guid + } + }; + + string token = await GetAuthToken(); + UriBuilder sequenceUriBuilder = new($"{url}/api/Sequences/sequence"); + string sequenceUrl = sequenceUriBuilder.ToString(); + await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "POST"); + } + + public async Task CreateAdminRoleToLatestDomain(string url, Guid roleGuid, int roleId, Guid userGuid, int userId) + { + var requestBody = new UserRoleIds + { + RoleId = new eSuite.Core.Miscellaneous.GeneralIdRef() + { + Guid = roleGuid, + Id = roleId + }, + UserId = new eSuite.Core.Miscellaneous.GeneralIdRef() + { + Guid = userGuid, + Id = userId + } + }; + + string token = await GetAuthToken(); + UriBuilder sequenceUriBuilder = new($"{url}/api/Role/roleUsers"); + string sequenceUrl = sequenceUriBuilder.ToString(); + await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "POST"); + } + + public async Task DeleteUserAPI(string url, Guid userGuid, int userId) + { + var requestBody = new GeneralIdRef + { + Guid = userGuid, + Id = userId + }; + + string token = await GetAuthToken(); + UriBuilder sequenceUriBuilder = new($"{url}/api/User/user"); + string sequenceUrl = sequenceUriBuilder.ToString(); + string ddd = JsonConvert.SerializeObject(requestBody); + var response = await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "DELETE"); + var r = await response.Content.ReadAsStringAsync(); + var statusCode = response.StatusCode; + } + + public async Task DeleteDomainAPI(string url, Guid userGuid, int userId) + { + var requestBody = new GeneralIdRef + { + Guid = userGuid, + Id = userId + }; + + string token = await GetAuthToken(); + UriBuilder sequenceUriBuilder = new($"{url}/api/Domain/domain"); + string sequenceUrl = sequenceUriBuilder.ToString(); + string ddd = JsonConvert.SerializeObject(requestBody); + var response = await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "DELETE"); + var r = await response.Content.ReadAsStringAsync(); + var statusCode = response.StatusCode; + } + + public void Dispose() + { + httpClient.Dispose(); + } + + internal void AssignAdminRoleToUser(string v) + { + throw new NotImplementedException(); + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AtributeHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AtributeHelper.cs new file mode 100644 index 0000000..feedfd4 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AtributeHelper.cs @@ -0,0 +1,9 @@ +namespace ESuite.UI.E2E.Helpers +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class RetryStepAttribute : Attribute + { + // For custom options + } + +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AuthenticationHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AuthenticationHelper.cs new file mode 100644 index 0000000..56bf643 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AuthenticationHelper.cs @@ -0,0 +1,87 @@ +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; +using OtpNet; + + +namespace ESuite.UI.E2E.Helpers +{ + public static class AuthenticationHelper + { + private readonly static IWebDriver driver = WebDriverHelper.GetWebDriver(); + + public static void LoginWithCredentials(string username, string password, string baseUrl) + { + LoginPage loginPage = new(driver); + + I.NavigateToURL($"{baseUrl}/login"); + + loginPage.EnterUserEmail(username); + I.Click(loginPage.NextButton); + loginPage.EnterPassword(password); + I.Click(loginPage.LoginButton); + } + + public static void LoginWithCredentials2FA(string username, string password, string baseUrl, ScenarioContext scenarioContext) + { + LoginPage loginPage = new(driver); + + I.NavigateToURL($"{baseUrl}/login"); + I.WaitForElementVisibleAndClickable(loginPage.EmailInput); + loginPage.EnterUserEmail(username); + I.Click(loginPage.NextButton); + I.WaitForElementVisibleAndClickable(loginPage.PasswordInput); + loginPage.EnterPassword(password); + I.Click(loginPage.LoginButton); + I.WaitForElementVisibleAndClickable(LoginPage.SecurityCodeInput); + + LoginPage.Enter2FACode(scenarioContext); + I.Click(loginPage.LoginButton); + } + + public static void Logout(string baseUrl) + { + _ = new LoginPage(driver); + var url = $"{baseUrl}/logout"; + + try + { + I.NavigateToURL(url); + } + catch (WebDriverException) + { + if (driver.Url == url) + return; + } + } + + public static string GenerateOTP(string secretKey, ScenarioContext scenarioContext) + { + var otpKeyStr = secretKey; + var otpKeyBytes = Base32Encoding.ToBytes(otpKeyStr); + var totp = new Totp(otpKeyBytes); + var codeExpiresIn = totp.RemainingSeconds(); + var twoFactorCode = totp.ComputeTotp(); + if (codeExpiresIn < 3) + { + I.DebounceDelay(codeExpiresIn + 5000); + twoFactorCode = totp.ComputeTotp(); + if (twoFactorCode != null) + { + scenarioContext["SecurityCode"] = $"{twoFactorCode}"; + return twoFactorCode; + } + else + { + throw new Exception("Error while generating OTP code."); + } + + } + else + { + scenarioContext["SecurityCode"] = $"{twoFactorCode}"; + return twoFactorCode; + } + + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AutomationTestManagerHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AutomationTestManagerHelper.cs new file mode 100644 index 0000000..b71cc04 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/AutomationTestManagerHelper.cs @@ -0,0 +1,374 @@ +using e_suite.Database.Core.Models; +using eSuite.Core.Sequences; +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; + + +namespace ESuite.UI.E2E.Helpers +{ + public class AutomationTestManagerHelper + { + private readonly IWebDriver driver; + private readonly ScenarioContext _scenarioContext; + private readonly APIHelper apiHelper; + private readonly ConfigHelper configHelper; + + public AutomationTestManagerHelper(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + _scenarioContext = scenarioContext; + apiHelper = new(_scenarioContext); + configHelper = new ConfigHelper(); + } + + private static readonly Dictionary auditEntityDisplayName = new() + { + { "Forms", "Forms" }, + { "Form Template", "Form Template" }, + { "Form Field Instance", "Form Field Instance" }, + { "Form Instance", "Form Instance" }, + { "Sequence", "Sequence" }, + { "Glossaries", "Glossary" }, + { "Glossary Item", "Glossary" }, + { "Glossary Custom Field Value", "Glossary Custom Field Value" }, + { "Custom Field", "Custom Field" }, + { "Client Domains", "Domain" }, + { "Users", "User" }, + { "Sso Manager", "Sso Provider" }, + { "Organisation", "Organisation" }, + { "Site", "Site" }, + { "Role", "Role" }, + { "Role Access", "RoleAccess" }, + { "UserRoles", "UserRoles" }, + { "Mail Template", "Mail Template" }, + { "Custom Field Glossary", "Custom Field Glossary" }, + { "Custom Field Sequence", "Custom Field Sequence" }, + { "Custom Field Number", "Custom Field Number" }, + { "Custom Field Text", "Custom Field Text" }, + { "Custom Field Form Template", "Custom Field" }, + { "Custom Field Domain", "Custom Field" }, + { "Specification", "Specification" } + }; + + public static Dictionary AuditEntityDisplayName { get => auditEntityDisplayName; } + + public void CreateSsoProvider() + { + _scenarioContext["SSOProviderName"] = "TestSsoProvider" + _scenarioContext["GUID"]; + string clientId = "778899937320-phjl4hpacmeele7k92650u5q73n66cqe.apps.googleusercontent.com"; + string clientSecret = "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"; + string validIssuer = "https://accounts.google.com"; + string authorisationEndpoint = "https://accounts.google.com/o/oauth2/auth"; + string tokenEndpoint = "https://oauth2.googleapis.com/token"; + Guid guid = new(_scenarioContext["GUID"].ToString()!); + string clientIdHidden = "", clientSecretHidden = ""; + bool isPublic = true; + _scenarioContext["SSOProviderCreated"] = $"{authorisationEndpoint}, {clientIdHidden}, {clientSecretHidden}, {false.ToString().ToLower()}, {guid}, {isPublic.ToString().ToLower()}, {_scenarioContext["SSOProviderName"]}, {tokenEndpoint}, {validIssuer}"; + Task.Run(async () => + { + await apiHelper.CreateNewSSOProvider( + configHelper.APIUrl, + _scenarioContext["SSOProviderName"].ToString()!, + clientId, + clientSecret, + validIssuer, + authorisationEndpoint, + tokenEndpoint, + isPublic, + guid + ); + }); + } + + public void DeleteSsoProvider() + { + DeleteEntity("Sso Manager", _scenarioContext["SSOProviderName"].ToString()!, _scenarioContext); + } + + public async Task CreateUser() + { + var firstName = "Wolfgang" + _scenarioContext["GUID"]; + var middleName = "Amadeus"; + var lastName = "Mozart"; + var email = "tww44@inbox.testmail.app" + _scenarioContext["GUID"]; + _scenarioContext["UserName"] = $"{firstName} {middleName} {lastName}"; + _scenarioContext["UserEmail"] = $"{email}"; + await Task.Run(async () => + { + var domains = await apiHelper.GetDomains(configHelper.APIUrl); + var data = domains["data"]!.ElementAt(0); + int domainId = (int)data["id"]!; + + await apiHelper.CreateNewUser( + configHelper.APIUrl, + firstName!, + middleName!, + lastName!, + email, + domainId + ); + }); + } + + public void DeleteUser() + { + DeleteEntity("Users", _scenarioContext["UserName"].ToString()!, _scenarioContext, AddUsersPage.DisplayNameSearchField); + } + + public async Task CreateOrganisation() + { + var name = "TestOrganisation" + _scenarioContext["GUID"]; + var address = "TestAddress"; + OrganisationStatus status = OrganisationStatus.Active; + Guid guid = new(_scenarioContext["GUID"].ToString()!); + + _scenarioContext!["OrganisationName"] = $"{name}"; + _scenarioContext["OrganisationCreated"] = $"{address}, {"false"}, {guid}, {name}, {status}"; + + await apiHelper.CreateNewOrganisation( + configHelper.APIUrl, + guid!, + name!, + address!, + status! + ); + } + + public void DeleteOrganisation() + { + I.Click(BasicPage.DropdownTab("e-print")); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!); + I.Click(BasicPage.DeleteOrganisationButton(_scenarioContext!["OrganisationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.DeleteOrganisationButton(_scenarioContext!["OrganisationName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.ConfirmDeletionButton); + } + + public void CreateSite() + { + var name = "TestOrganisationSite" + _scenarioContext["GUID"]; + var address = "TestAddress"; + OrganisationStatus status = OrganisationStatus.Active; + Guid guid = new(_scenarioContext["GUID"].ToString()!); + + _scenarioContext!["SiteName"] = $"{name}"; + _scenarioContext["SiteCreated"] = $"{address}, {"false"}, {guid}, {name}, {_scenarioContext["OrganisationName"]}, {""}, {status}"; + + Task.Run(async () => + { + var organisations = await apiHelper.GetOrganisations(configHelper.APIUrl); + var data = organisations["data"]!.ElementAt(0); + int organisationId = (int)data["id"]!; + await apiHelper.CreateNewSite( + configHelper.APIUrl, + guid!, + name!, + address!, + status!, + organisationId + ); + }); + } + + public void DeleteSite() + { + I.Click(BasicPage.DropdownTab("e-print")); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!); + I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!)); + I.Click(BasicPage.DeleteOrganisationButton(_scenarioContext!["SiteName"].ToString()!)); + I.WaitTillInvisible(BasicPage.DeleteOrganisationButton(_scenarioContext!["SiteName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.ConfirmDeletionButton); + } + + public void SaveDataFromCreatedUser() + { + Task.Run(async () => + { + var users = await apiHelper.GetUsers(configHelper.APIUrl); + var data = users["data"]!.ElementAt(0); + int userId = (int)data["id"]!; + string userGuid = (string)data["guid"]!; + string userFirstName = (string)data["firstName"]!; + string userLastName = (string)data["lastName"]!; + string userMiddleName = (string)data["middleNames"]!; + string userDomainName = (string)data["domainName"]!; + string userEmail = (string)data["email"]!; + string userCreatedDate = (string)data["created"]!; + var userEmailConfirmed = (string)data["emailConfirmed"]!; + _scenarioContext["UserCreated"] = $"{"true"}, {userCreatedDate}, {userDomainName}, {userEmail}, {userEmailConfirmed.ToLower()}, {userFirstName}, {userGuid}," + + $" {userLastName}, {userMiddleName}, {""}, {""}, {""}, {""}, {"false"}"; + }); + } + + public async Task CreateDomain(string name) + { + + if (string.IsNullOrEmpty(name)) + { + name = "TestDomain" + _scenarioContext["GUID"]; + } + + var sunriseHostName = ""; + var sunriseAppId = ""; + var sunriseCategoryId = ""; + int? sigmaId = null; + Guid guid = Guid.NewGuid(); + + _scenarioContext!["DomainName"] = $"{name}"; + _scenarioContext["DomainCreated"] = $"{"false"}, {guid}, {name}, {""}, {""}, {""}, {""}, {""}"; + + await apiHelper.CreateNewDomain( + configHelper.APIUrl, + guid!, + name!, + sunriseHostName, + sunriseAppId, + sunriseCategoryId, + sigmaId + ); + } + + public void CreateRole() + { + _scenarioContext["DomainRoleName"] = "Role" + _scenarioContext["GUID"]; + var name = _scenarioContext["DomainRoleName"].ToString()!; + Guid guid = new(_scenarioContext["GUID"].ToString()!); + var isSuperUser = false; + var isAdministrator = false; + var canDelete = true; + _scenarioContext["RoleCreated"] = $"{canDelete.ToString().ToLower()}, {false.ToString().ToLower()}, {_scenarioContext["DomainName"]}, {guid}, {isAdministrator.ToString().ToLower()}, {isSuperUser.ToString().ToLower()}, {name}"; + + Task.Run(async () => + { + var domains = await apiHelper.GetDomains(configHelper.APIUrl); + var data = domains["data"]!.ElementAt(0); + int domainId = (int)data["id"]!; + + await apiHelper.CreateNewRole( + configHelper.APIUrl, + name!, + guid!, + isSuperUser!, + isAdministrator, + domainId + ); + }); + } + + public async Task CreateSequence(string? newName = null) + { + _scenarioContext["SequenceName"] = (newName ?? "Sequence") + _scenarioContext["GUID"]; + var name = _scenarioContext["SequenceName"].ToString()!; + Guid guid = new(_scenarioContext["GUID"].ToString()!); + Rollover rollOver = Rollover.Day; + int seed = 1; + int increment = 1; + var pattern = "ID:[000000] Date:{DD}"; + + await Task.Run(async () => + { + await apiHelper.CreateNewSequence( + configHelper.APIUrl, + name!, + seed!, + increment!, + pattern, + rollOver, + guid! + ); + }); + } + + public async Task AssignAdminRole(int userId, Guid userGuid) + { + var roles = await apiHelper.GetRoles(configHelper.APIUrl); + var data = roles["data"]!.ElementAt(0); + int roleId = (int)data["id"]!; + Guid roleGuid = Guid.Parse((string)data["guid"]!); + await apiHelper.CreateAdminRoleToLatestDomain( + configHelper.APIUrl, + roleGuid!, + roleId!, + userGuid!, + userId! + ); + } + + public async Task DeleteUserAPI() + { + var userId = int.Parse(_scenarioContext["UserId"].ToString()!); + Guid userGuid = new(_scenarioContext["UserGUID"].ToString()!); + + await apiHelper.DeleteUserAPI( + configHelper.APIUrl, + userGuid!, + userId! + ); + } + + public async Task DeleteDomainAPI() + { + var domainId = int.Parse(_scenarioContext["DomainId"].ToString()!); + Guid domainGuid = new(_scenarioContext["DomainGUID"].ToString()!); + + await apiHelper.DeleteDomainAPI( + configHelper.APIUrl, + domainGuid!, + domainId! + ); + } + + public void DeleteDomain() + { + DeleteEntity("Client Domains", _scenarioContext["DomainName"].ToString()!, _scenarioContext); + } + + public void DeleteFormTemplate() + { + DeleteEntity("Forms", _scenarioContext["FormName"].ToString()!, _scenarioContext); + } + + public static void DeleteEntity(string menuName, string entityName, ScenarioContext scenarioContext, By? locator = null) + { + try + { + NavigateToMenu(menuName); + BasicPage.SearchObjectNameInTableViaSearchInputField(entityName, locator); + I.Click(BasicPage.DeleteObjectButton(entityName)); + I.WaitTillInvisible(BasicPage.DeleteObjectButton(entityName)); + I.Click(BasicPage.ConfirmDeletionButton); + SaveTimingForAction(scenarioContext); + I.WaitTillInvisible(BasicPage.ConfirmDeletionButton); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to delete entity '{entityName}' in menu '{menuName}': {ex.Message}"); + throw; + } + } + + public static void SaveTimingForAction(ScenarioContext scenarioContext) + { + DateTimeOffset currentDateAndTime = DateTimeOffset.Now; + string formattedDate = currentDateAndTime.ToString("MMM d, yy, hh:mm tt"); + scenarioContext["Timing"] = formattedDate; + } + + public static void NavigateToMenu(string menuName) + { + try + { + BasicPage.ClickOnDropdownMenuItem(menuName); + //I.WaitForElementVisibleAndClickable(BasicPage.SearchInput); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to navigate to menu '{menuName}': {ex.Message}"); + throw; + } + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/ConfigHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/ConfigHelper.cs new file mode 100644 index 0000000..929a46f --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/ConfigHelper.cs @@ -0,0 +1,24 @@ +namespace ESuite.UI.E2E.Helpers +{ + public class ConfigHelper : AutomationTestBase + { + public bool HeadlessMode { get; set; } + public string BaseUrl { get; set; } + public int ClickWaitSeconds { get; set; } + public string AdminName { get; set; } + public string AdminPassword { get; set; } + public string APIUrl { get; set; } + public int DebounceDelayMilliseconds { get; set; } + + public ConfigHelper() : base() + { + HeadlessMode = TestEnvironment.HeadlessMode; + BaseUrl = TestEnvironment.BaseUrl; + ClickWaitSeconds = TestEnvironment.ClickWaitSeconds; + AdminName = TestEnvironment.Username; + AdminPassword = TestEnvironment.Password; + APIUrl = TestEnvironment.APIUrl; + DebounceDelayMilliseconds = TestEnvironment.DebounceDelayMilliseconds; + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/I.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/I.cs new file mode 100644 index 0000000..f7e5de6 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/I.cs @@ -0,0 +1,436 @@ +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; +using OpenQA.Selenium.Support.UI; +using SeleniumExtras.WaitHelpers; + +namespace ESuite.UI.E2E.Helpers +{ + public static class I + { + private readonly static ConfigHelper configHelper = new(); + private readonly static int TimeToWait = configHelper.ClickWaitSeconds; + public static void Click(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + IWebElement? element = WaitForElementVisibleAndClickable(locator, (int)waitTimeInSeconds, driver) ?? throw new NoSuchElementException($"Element with locator '{locator}' was not found."); + + try + { + element.Click(); + } + catch (Exception) + { + IWebElement? newPositionElement = WaitForElementVisibleAndClickable(locator, (int)waitTimeInSeconds, driver); + newPositionElement!.Click(); + } + } + + public static void RefreshPage(IWebDriver? driver = null) + { + driver ??= WebDriverHelper.GetWebDriver(); + + driver!.Navigate().Refresh(); + } + + public static IWebElement? WaitForVisible(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + return Retry((int)waitTimeInSeconds, () => + { + return wait.Until(ExpectedConditions.ElementIsVisible(locator)); + }); + } + + private static T Retry(int waitTimeInSeconds, Func func) + { + var expire = DateTime.Now.AddSeconds((int)waitTimeInSeconds); + Exception? exception = null; + + while (DateTime.Now < expire) + { + try + { + return func(); + } + catch (Exception e) + { + exception = e; + } + } + throw new Exception("Retry failed", exception); + } + + private static void Retry(int waitTimeInSeconds, Action func) + { + var expire = DateTime.Now.AddSeconds((int)waitTimeInSeconds); + Exception? exception = null; + + while (DateTime.Now < expire) + { + try + { + func(); + exception = null; + + break; + } + catch (Exception e) + { + exception = e; + } + + } + + if (exception != null) + { + throw new Exception("Retry failed", exception); + } + } + + public static IWebElement? WaitForElementVisibleAndClickable(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + return Retry((int)waitTimeInSeconds, () => + { + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + try + { + wait.Until(ExpectedConditions.ElementIsVisible(locator)); + return wait.Until(ExpectedConditions.ElementToBeClickable(locator)); + } + catch (StaleElementReferenceException) + { + throw; + } + catch (NoSuchElementException) + { + return null; + } + }); + } + + public static IWebElement? WaitToBeClickable(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + return Retry((int)waitTimeInSeconds, () => + { + try + { + return wait.Until(ExpectedConditions.ElementToBeClickable(locator)); + } + catch (StaleElementReferenceException) + { + throw; + } + catch (NoSuchElementException) + { + return null; + } + }); + } + + public static bool WaitTillInvisible(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + try + { + return wait.Until(ExpectedConditions.InvisibilityOfElementLocated(locator)); + } + catch (NoSuchElementException) + { + return false; + } + } + + public static void FillField(By locator, string text, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + IWebElement? element = WaitToBeClickable(locator, (int)waitTimeInSeconds, driver); + + if (element != null) + { + element.Clear(); + DebounceDelay(300); + element.SendKeys(text); + + if (element.TagName.Equals("input", StringComparison.CurrentCultureIgnoreCase)) + { + WaitForElementWithAttributeValue(locator, "value", text); + } + } + else + { + throw new InvalidOperationException($"There is not input field with locator: {locator}"); + } + } + + public static void WaitForElementWithAttributeValue(By locator, string attributeName, string expectedValue, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + try + { + wait.Until(driver => + { + var element = driver.FindElement(locator); + var actualValue = element.GetAttribute(attributeName); + + return actualValue == expectedValue; + }); + } + catch (WebDriverTimeoutException) + { + throw new TimeoutException($"Element with locator '{locator}', attribute '{attributeName}' and expected value '{expectedValue}' was not found!"); + } + } + + public static void WaitForOptionToBePresentInSelect(By selectLocator, string optionText, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + BasicPage basicPage = new(driver); + WaitTillInvisible(BasicPage.LoadingDropdownMessage); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + wait.Until(driver => + { + var selectElement = driver.FindElement(selectLocator); + var option = selectElement.FindElements(By.XPath($"./option[text()='{optionText}']")); + + return option.Count > 0; + }); + } + + public static void SelectOption(By locator, object option, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + string? optionString = option.ToString(); + + Retry((int)waitTimeInSeconds, () => + { + IWebElement? element = WaitForElementVisibleAndClickable(locator, (int)waitTimeInSeconds, driver); + WaitForOptionToBePresentInSelect(locator, optionString!); + + try + { + SelectElement select = new(element!); + select.SelectByText(optionString!); + } + catch (StaleElementReferenceException) + { + throw; + } + catch (Exception e) + { + throw new NoSuchElementException($"Option '{option}' was not found. Exception: {e.Message}"); + } + }); + } + + public static string GetText(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + try + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + IWebElement? element = WaitForElementVisibleAndClickable(locator, (int)waitTimeInSeconds, driver); + + return element!.Text; + } + catch (NoSuchElementException) + { + throw new NoSuchElementException($"I can't find the text for a non-existent locator: {locator}"); + } + } + + public static bool CheckIfTextInChildElements(By locator, string searchText, IWebDriver? driver = null) + { + driver ??= WebDriverHelper.GetWebDriver(); + + IWebElement? parentElement = driver!.FindElement(locator); + IReadOnlyCollection childElements = parentElement.FindElements(By.XPath(".//*")); + + foreach (IWebElement child in childElements) + { + if (child.Text.Contains(searchText)) return true; + } + + return false; + } + + public static bool CheckIfTextIs(By locator, string searchText, IWebDriver? driver = null) + { + driver ??= WebDriverHelper.GetWebDriver(); + IWebElement? element = driver!.FindElement(locator); + if (element.Text.Contains(searchText)) return true; + + return false; + } + + public static string GetValueAttribute(By locator, int? waitTimeInSeconds = null, string? attributeName = "value", IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + IWebElement? element = WaitForVisible(locator, (int)waitTimeInSeconds, driver); + + return element!.GetAttribute(attributeName!)!; + } + + public static string GetTextFromElement(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + try + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + IWebElement? element = WaitForElementVisibleAndClickable(locator, (int)waitTimeInSeconds, driver); + + return element!.Text; + } + catch (NoSuchElementException) + { + throw new NoSuchElementException($"I can't find elements for a non-existent locator: {locator}"); + } + } + + public static IList GetTextsFromElements(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + try + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + WaitForElementVisibleAndClickable(locator, (int)waitTimeInSeconds, driver); + var elements = driver.FindElements(locator); + + IList texts = []; + + foreach (var element in elements) + { + texts.Add(element.Text); + } + + return texts; + } + catch (NoSuchElementException) + { + throw new NoSuchElementException($"I can't find elements for a non-existent locator: {locator}"); + } + } + + public static int CountElementsOnPage(By locator, IWebDriver? driver = null) + { + driver ??= WebDriverHelper.GetWebDriver(); + System.Collections.ObjectModel.ReadOnlyCollection webElements = driver.FindElements(locator); + + return ((IReadOnlyCollection)webElements).Count; + } + + public static bool IsVisibleNumberOfElements(By locator, int numberOfElements, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + try + { + return wait.Until(drv => drv.FindElements(locator).Count == numberOfElements); + } + catch (WebDriverTimeoutException) + { + return false; + } + } + + /// + /// Delays the execution for the specified amount of time in milliseconds. + /// + /// The time to wait. + public static void DebounceDelay(int time) + { + Thread.Sleep(time); + } + + public static void WaitForPageToLoad(int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + driver ??= WebDriverHelper.GetWebDriver(); + waitTimeInSeconds ??= TimeToWait; + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + wait.Until(driver => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState")!.Equals("complete")); + } + + public static void NavigateToURL(string url, IWebDriver? driver = null) + { + driver ??= WebDriverHelper.GetWebDriver(); + driver.Navigate().GoToUrl(url); + WaitForPageToLoad(); + } + + public static bool WaitForElementToBeChecked(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + try + { + return wait.Until(ExpectedConditions.ElementToBeSelected(locator)); + } + catch (Exception) + { + return false; + } + } + + public static String? ReturnSelectedOption(By locator, int? waitTimeInSeconds = null, IWebDriver? driver = null) + { + waitTimeInSeconds ??= TimeToWait; + driver ??= WebDriverHelper.GetWebDriver(); + + WebDriverWait wait = new(driver, TimeSpan.FromSeconds((int)waitTimeInSeconds)); + + try + { + return wait.Until(driver => + { + IWebElement selectElement = driver.FindElement(locator); + SelectElement select = new(selectElement); + string selectedText = select.SelectedOption.Text; + + return selectedText; + }); + } + catch (WebDriverTimeoutException) + { + return null; + throw new TimeoutException($"Element with locator '{locator}' was not found!"); + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/Mail/MailHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/Mail/MailHelper.cs new file mode 100644 index 0000000..4424576 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/Mail/MailHelper.cs @@ -0,0 +1,187 @@ +using Newtonsoft.Json.Linq; + +namespace ESuite.UI.E2E.Helpers.Mail +{ + public class Mailer + { + + public static string CustomizeUserEmail(string email, string customText) + { + string[] parts = email.Split('@'); + if (parts.Length == 2) + { + string firstPart = parts[0]; + string domainPart = parts[1]; + firstPart += $".{customText}"; + string modifiedEmail = $"{firstPart}@{domainPart}"; + + return modifiedEmail; + } + else + { + throw new Exception($"Email '{email}' should have one sign '@'!"); + } + } + + public static async Task GetIdFromPapercutAsync() + { + try + { + string apiUrl = "http://localhost:37408/api/messages?limit=1"; + + using HttpClient client = new(); + HttpResponseMessage response = await client.GetAsync(apiUrl); + + if (response.IsSuccessStatusCode) + { + string content = await response.Content.ReadAsStringAsync(); + dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(content) ?? throw new Exception("Deserialized JSON is null"); + string id = json!.Messages[0].Id; + + return id; + } + else + { + throw new Exception($"Response is: {response.StatusCode}"); + } + } + catch (Exception ex) + { + return $"Error: {ex.Message}"; + } + } + private static string GetLinkFromBodyMessage(string text, string? startSymbols = "http", string? endSymbols = "\"") + { + int startIndex = text.IndexOf(startSymbols!); + int endIndex = text.IndexOf(endSymbols!, startIndex); + + if (startIndex != -1 && endIndex != -1) + { + string url = text[startIndex..endIndex]; + + return url; + } + else + { + throw new Exception($"I can't find the link"); + } + } + + public static async Task GetLinkFromHtmlBodyViaPapercut(string id, string? LinkText = "") + { + try + { + string apiUrl = $"http://localhost:37408/api/messages/{id}"; + + using HttpClient client = new(); + HttpResponseMessage response = await client.GetAsync(apiUrl); + + if (response.IsSuccessStatusCode) + { + string content = await response.Content.ReadAsStringAsync(); + + if (!string.IsNullOrEmpty(content)) + { + dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(content) ?? throw new Exception("Deserialized JSON is null"); + string htmlBody = json!.HtmlBody; + return GetLinkFromBodyMessage(htmlBody); + + } + else + { + throw new Exception("Received empty or null content."); + } + } + else + { + throw new Exception($"Response status is: {response.StatusCode}"); + } + } + catch (Exception ex) + { + return $"Error: {ex.Message}"; + } + } + + public static async Task GetLinkFromHtmlBodyViaTestMailApp(string clientEmail, string apiKey, string nameSpace, int retryCount = 0) + { + if (string.IsNullOrEmpty(apiKey)) + { + throw new Exception("API key is empty! Check release variables!"); + } + + try + { + string apiUrl = $"https://api.testmail.app/api/json?apikey={apiKey}&namespace={nameSpace}"; + + using HttpClient client = new(); + HttpResponseMessage response = await client.GetAsync(apiUrl); + + if (response.IsSuccessStatusCode) + { + string content = await response.Content.ReadAsStringAsync(); + + if (!string.IsNullOrEmpty(content)) + { + dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(content) ?? throw new Exception("Deserialized JSON is null"); + + try + { + if (json.emails != null && !string.IsNullOrEmpty(json.emails[0].html.ToString())) + { + + JArray emails = (JArray)json["emails"]; + + foreach (JObject email in emails.Cast()) + { + JObject toParsed = (JObject)email["to_parsed"]![0]!; + string address = (string)toParsed["address"]!; + + if (address == clientEmail) + { + return GetLinkFromBodyMessage((string)email["html"]!); + } + else + { + throw new Exception($"I can't find the email with the recipient: {clientEmail}"); + } + } + throw new Exception("I can't find address in email"); + } + else + { + throw new Exception("Empty emails"); + } + } + catch (Exception) + { + if (retryCount < 3) + { + await Task.Delay(TimeSpan.FromMinutes(1)); + + return await GetLinkFromHtmlBodyViaTestMailApp(clientEmail, apiKey, nameSpace, retryCount + 1); + } + else + { + throw new Exception("Exceeded maximum retry limit to get Email."); + } + } + } + else + { + throw new Exception("Received empty or null content."); + } + } + else + { + throw new Exception($"Response status is: {response.StatusCode}"); + } + } + catch (Exception ex) + { + return $"Error: {ex.Message}"; + } + } + + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/RetryHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/RetryHelper.cs new file mode 100644 index 0000000..c527944 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/RetryHelper.cs @@ -0,0 +1,27 @@ +namespace ESuite.UI.E2E.Helpers +{ + public class RetryHelper + { + public static void Retry(Action action, int maxRetries = 3, int delayInMilliseconds = 1500) + { + int attempts = 0; + while (true) + { + try + { + attempts++; + action(); + return; + } + catch (Exception ex) + { + if (attempts >= maxRetries) + throw new Exception($"Action failed after {maxRetries} retries.", ex); + + Console.WriteLine($"Attempt {attempts} failed: {ex.Message}. Retrying in {delayInMilliseconds}ms..."); + Thread.Sleep(delayInMilliseconds); + } + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/WebDriverHelper.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/WebDriverHelper.cs new file mode 100644 index 0000000..bf266b4 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Helpers/WebDriverHelper.cs @@ -0,0 +1,68 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; + +namespace ESuite.UI.E2E.Helpers +{ + public static class WebDriverHelper + { + private static IWebDriver? driver; + private readonly static ConfigHelper configHelper = new(); + public static void InitializeWebDriver() + { + driver = CreateWebDriverWithDefaultResolution(); + } + + private static IWebDriver CreateWebDriverWithDefaultResolution() + { + ChromeOptions options = new(); + options.AddArgument("window-size=1920,1080"); + options.AddArgument("--enable-javascript"); + + if (configHelper.HeadlessMode) + { + options.AddArgument("headless"); + options.AddArgument("disable-gpu"); + } + else + { + options.AddArgument("--start-maximized"); + } + + + driver = new ChromeDriver(options); + return driver; + } + + public static IWebDriver GetWebDriver() + { + driver ??= CreateWebDriverWithDefaultResolution(); + + return driver; + } + + public static byte[]? CaptureScreenshot() + { + driver ??= GetWebDriver(); + + try + { + var screenshot = ((ITakesScreenshot)driver).GetScreenshot(); + return screenshot.AsByteArray; + } + catch (Exception ex) + { + Console.WriteLine($"Error capturing screenshot: {ex.Message}"); + return null; + } + } + + public static void QuitWebDriver() + { + if (driver != null) + { + driver.Quit(); + driver = null; + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Hooks/ScenarioHooks.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Hooks/ScenarioHooks.cs new file mode 100644 index 0000000..8ed9193 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Hooks/ScenarioHooks.cs @@ -0,0 +1,47 @@ +using ESuite.UI.E2E.Helpers; + +namespace ESuite.UI.E2E.Hooks +{ + + [Binding] + public class ScenarioHooks + { + private readonly ScenarioContext _scenarioContext; + private readonly APIHelper _apiHelper; + + public ScenarioHooks(ScenarioContext scenarioContext) + { + _scenarioContext = scenarioContext; + _apiHelper = new APIHelper(_scenarioContext); + + } + + [BeforeScenario(Order = 2)] + public void SetGUIDs() + { + string uniqueGuid = Guid.NewGuid().ToString().TrimStart('{').TrimEnd('}'); + _scenarioContext["GUID"] = uniqueGuid; + _scenarioContext["GUIDPrefix"] = $"{uniqueGuid}-"; + _scenarioContext["GUIDPostfix"] = $"-{uniqueGuid}"; + } + + [BeforeScenario] + public void CleanAuthToken() + { + _apiHelper.ClearAuthToken(); + } + + [BeforeStep] + [AfterStep] + public static void RetryFailedStep(ScenarioContext scenarioContext) + { + if (scenarioContext.TestError != null) + { + RetryHelper.Retry(() => + { + Console.WriteLine("Retrying failed step..."); + }); + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/ImplicitUsings.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/ImplicitUsings.cs new file mode 100644 index 0000000..98a7ae6 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/ImplicitUsings.cs @@ -0,0 +1,3 @@ +global using Reqnroll; +global using e_suite.UnitTestCore; +global using Autofac; \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/AuditData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/AuditData.cs new file mode 100644 index 0000000..e1273d4 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/AuditData.cs @@ -0,0 +1,14 @@ +namespace ESuite.UI.E2E.Models +{ + public class AuditData + { + public string? Timing { get; set; } + public string? UserName { get; set; } + public string? Comment { get; set; } + public string? EntityDisplayName {get; set; } + public string? Type {get; set; } + public string? DisplayName { get; set; } + public string? Changes { get; set; } + public int? NumberOfLogs { get; set; } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/CustomFieldsData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/CustomFieldsData.cs new file mode 100644 index 0000000..a8d68f8 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/CustomFieldsData.cs @@ -0,0 +1,17 @@ +namespace ESuite.UI.E2E.Models +{ + public class CustomFieldsData + { + public string? Name { get; set; } + public string? FieldType { get; set; } + public string? DefaultValue { get; set; } + public string? Sequence { get; set; } + public string? Glossary { get; set; } + public string? MinimumValue { get; set; } + public string? MaximumValue { get; set; } + public string? Step { get; set; } + public string? Required { get; set; } + public string? MultiLine { get; set; } + public string? MaxEntries { get; set; } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/DomainsData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/DomainsData.cs new file mode 100644 index 0000000..fb3e71c --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/DomainsData.cs @@ -0,0 +1,13 @@ +namespace ESuite.UI.E2E.Models +{ + public class DomainsData + { + public string? Name { get; set; } + public string? RoleName { get; set; } + public string? TemplateName { get; set; } + public string? Subject { get; set; } + public string? Definition { get; set; } + public string? SSOProvider { get; set; } + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/EmailData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/EmailData.cs new file mode 100644 index 0000000..e6844be --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/EmailData.cs @@ -0,0 +1,8 @@ +namespace ESuite.UI.E2E.Models +{ + public class EmailData + { + public string? Subject { get; set; } + public string? LinkText { get; set; } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/FormTemplateData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/FormTemplateData.cs new file mode 100644 index 0000000..4697890 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/FormTemplateData.cs @@ -0,0 +1,16 @@ +namespace ESuite.UI.E2E.Models +{ + public class FormTemplateData + { + public string? Name { get; set; } + public string? ChildFormName { get; set; } + public bool NeedTable { get; set; } + public int TotalNumberOfColumns { get; set; } + public int ColumnNumber { get; set; } + public int TotalNumberOfRows { get; set; } + public int RowNumber { get; set; } + public string? CustomFields { get; set; } + public string? Text { get; set; } + public int Version { get; set; } = 1; + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/GlossariesData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/GlossariesData.cs new file mode 100644 index 0000000..3fbac50 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/GlossariesData.cs @@ -0,0 +1,9 @@ +namespace ESuite.UI.E2E.Models +{ + public class GlossariesData + { + public string? Name { get; set; } + public string? Add { get; set; } + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/GlossaryItemData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/GlossaryItemData.cs new file mode 100644 index 0000000..e75108a --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/GlossaryItemData.cs @@ -0,0 +1,9 @@ +namespace ESuite.UI.E2E.Models +{ + public class GlossaryItemData + { + public string? Name { get; set; } + public string? CustomField { get; set; } + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/OrganisationsData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/OrganisationsData.cs new file mode 100644 index 0000000..46d8692 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/OrganisationsData.cs @@ -0,0 +1,10 @@ +namespace ESuite.UI.E2E.Models +{ + public class OrganisationsData + { + public string? Name { get; set; } + public string? Address { get; set; } + public string? Status { get; set; } + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/PermissionsData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/PermissionsData.cs new file mode 100644 index 0000000..e937d8a --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/PermissionsData.cs @@ -0,0 +1,10 @@ +namespace ESuite.UI.E2E.Models +{ + public class PermissionsData + { + public string? Allowed { get; set; } + public string? Name { get; set; } + public string? Group { get; set; } + public string? Description { get; set; } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SequenceData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SequenceData.cs new file mode 100644 index 0000000..7687e65 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SequenceData.cs @@ -0,0 +1,11 @@ +namespace ESuite.UI.E2E.Models +{ + public class SequenceData + { + public string? Name { get; set; } + public string? Seed { get; set; } + public string? Increment { get; set; } + public string? Pattern { get; set; } + public string? RolloverType { get; set; } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SiteData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SiteData.cs new file mode 100644 index 0000000..bc22548 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SiteData.cs @@ -0,0 +1,10 @@ +namespace ESuite.UI.E2E.Models +{ + public class SiteData + { + public string? Name { get; set; } + public string? Address { get; set; } + public string? Status { get; set; } + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SpecificationsData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SpecificationsData.cs new file mode 100644 index 0000000..abc4ed7 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SpecificationsData.cs @@ -0,0 +1,13 @@ +namespace ESuite.UI.E2E.Models +{ + public class SpecificationsData + { + public string? Name { get; set; } + public string? PrintSpecification { get; set; } + public string? SpecificationItems { get; set; } + public string? ItemValue { get; set; } + public string? Message { get; set; } + public bool MultiselectField { get; set; } + public int NumberOfItems { get; set; } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SsoData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SsoData.cs new file mode 100644 index 0000000..fde5b9c --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/SsoData.cs @@ -0,0 +1,13 @@ +namespace ESuite.UI.E2E.Models +{ + public class SsoData + { + public string? Name { get; set; } + public string? ClientID { get; set; } + public string? ClientSecret { get; set; } + public string? ValidIssuer { get; set; } + public string? AuthorisationEndpoint { get; set; } + public string? TokenEndpoint { get; set; } + public string? IsPublic { get; set; } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Models/UsersData.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/UsersData.cs new file mode 100644 index 0000000..794e488 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Models/UsersData.cs @@ -0,0 +1,18 @@ +namespace ESuite.UI.E2E.Models +{ + public class UsersData + { + public string? Mail { get; set; } + public string? FirstName { get; set; } + public string? MiddleNames { get; set; } + public string? LastName { get; set; } + public string? Domain { get; set; } + public string? UserName { get; set; } + public string? EditedFirstName { get; set; } + public string? EditedMiddleNames { get; set; } + public string? EditedLastName { get; set; } + public string? Password { get; set; } + public string? FormMessage { get; set; } + public string? MFA { get; set; } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddCustomFieldsPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddCustomFieldsPage.cs new file mode 100644 index 0000000..4a7e0c4 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddCustomFieldsPage.cs @@ -0,0 +1,20 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddCustomFieldsPage + { + + // Page elements + public static By FieldTypeSelector => By.CssSelector("#fieldType"); + public static By DefaultValueField => By.CssSelector("#defaultValue"); + public static By CheckBox => By.CssSelector(".form-check-input"); + public static By MinValueField => By.CssSelector("#minValue"); + public static By MaxValueField => By.CssSelector("#maxValue"); + public static By MaxEntriesField => By.CssSelector("#maxEntries"); + public static By StepField => By.CssSelector("#step"); + + // Page actions + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddFormTemplatePage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddFormTemplatePage.cs new file mode 100644 index 0000000..cfddebb --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddFormTemplatePage.cs @@ -0,0 +1,55 @@ +using ESuite.UI.E2E.Helpers; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddFormTemplatePage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public AddFormTemplatePage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By InsertFieldButton => By.XPath("//button/span[text()='Insert Field']"); + public static By CustomFieldDropdownItem(string? name) => By.XPath($"//span[contains(@class,'ck-button__label')][text()='{name}']"); + public static By DefinitionTextBox => By.XPath("//div[contains(@class,'ck-editor__editable')][@role='textbox']"); + public static By InsertTableButton => By.XPath("//button[@data-cke-tooltip-text='Insert table']"); + public static By InsertTableDropdownGrid => By.ClassName("ck-insert-table-dropdown__grid"); + public static By CellTextbox(int row, int column) => By.XPath($"//div[@role='textbox']//figure/table/tbody/tr[{row}]/td[{column}]/span"); + public static By FormTemplateVersionByName(string name) => By.XPath($"//td[text()='{name}']/following-sibling::td"); + + // Page actions + public static void CreateTableViaGrid(int row, int column) + { + By coordinates = By.XPath($"//button[@data-row='{row}'][@data-column='{column}']"); + + I.Click(InsertTableButton); + I.WaitForVisible(InsertTableDropdownGrid); + I.Click(coordinates); + + } + + public static void ChooseCustomField(string? customField, int row, int column) + { + I.Click(CellTextbox(row, column)); + I.Click(InsertFieldButton); + I.Click(CustomFieldDropdownItem(customField)); + } + + public static void FillFieldTextInForm(string text, int row, int column) + { + I.Click(CellTextbox(row, column)); + I.FillField(CellTextbox(row, column), text); + } + + public static int GetFormVersionTemplateByName(string name) + { + var version = I.GetTextFromElement(FormTemplateVersionByName(name)); + return int.Parse(version); + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddGlossariesPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddGlossariesPage.cs new file mode 100644 index 0000000..3d34306 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddGlossariesPage.cs @@ -0,0 +1,19 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddGlossariesPage + { + + // Page elements + public static By PrintSpecificationFormTemplateFieldSelector => By.Id("customfield_1"); + public static By CustomFieldsSelector => By.CssSelector("select#customField"); + public static By PlusButton => By.CssSelector("button.btn-primary:not([disabled]) .fa-plus"); + public static By SearchGlossaryNameInTable(string? name) => By.XPath($"//table[contains(@class,'table-bordered')]//a[text()='{name}']"); + + public static By FormSelector => By.XPath("//select[@class='form-control'][text()='TestCF_formT']"); + + // Page actions + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddGlossaryItemPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddGlossaryItemPage.cs new file mode 100644 index 0000000..9fd5fb6 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddGlossaryItemPage.cs @@ -0,0 +1,24 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddGlossaryItemPage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public AddGlossaryItemPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By UpButton => By.XPath("//*[contains(@class,'btn-primary')][text()='Up']"); + public static By EditButton => By.XPath("//*[contains(@class,'btn-primary')][text()='Edit']"); + public static By AddSelector => By.XPath("//label[text()='Add']/following-sibling::select"); + + + // Page actions + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSequencePage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSequencePage.cs new file mode 100644 index 0000000..fc15358 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSequencePage.cs @@ -0,0 +1,25 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddSequencePage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public AddSequencePage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By SeedField => By.CssSelector("#seed"); + public static By IncrementField => By.CssSelector("#increment"); + public static By PatternField => By.CssSelector("#pattern"); + public static By RolloverTypeSelector => By.CssSelector("#rolloverType"); + + + // Page actions + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSpecificationsPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSpecificationsPage.cs new file mode 100644 index 0000000..5f18435 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSpecificationsPage.cs @@ -0,0 +1,24 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddSpecificationsPage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public AddSpecificationsPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By PrintSpecificationSelector => By.CssSelector("#printSpecifications"); + public static By PrintSpecificationGlossaryItemField => By.CssSelector(".form-control .autocomplete-text-input"); + public static By PrintSpecificationSelectItem(string text) => By.XPath($"//div[contains(@class,'ck-content')]//tr[td[contains(text(),'{text}')]]//div/select"); + public static By PrintSpecificationMultiSelectField => By.CssSelector(".multiSelect .form-control .autocomplete-text-input"); + public static By PrintSpecificationMultiSelectItem(string text) => By.XPath($"//div[contains(@class,'ck-content')]//tr//button[contains(text(),'{text}')]/parent::li"); + public static By PrintSpecificationTextAreaItem(string text) => By.XPath($"//div[contains(@class,'ck-content')]//tr[td[contains(text(),'{text}')]]//div/textarea"); + public static By PrintSpecificationInputItem(string text) => By.XPath($"//div[contains(@class,'ck-content')]//tr[td[contains(text(),'{text}')]]//div/input"); + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSsoProvider.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSsoProvider.cs new file mode 100644 index 0000000..d096866 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddSsoProvider.cs @@ -0,0 +1,25 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddSsoProvider + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public AddSsoProvider(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By NameField => By.CssSelector("input#name"); + public static By ClientIDField => By.CssSelector("input#clientId"); + public static By ClientSecretField => By.CssSelector("input#clientSecret"); + public static By ValidIssuerField => By.CssSelector("input#validIssuer"); + public static By AuthorisationEndpointField => By.CssSelector("input#authorizationEndpoint"); + public static By TokenEndpointField => By.CssSelector("input#tokenEndpoint"); + public static By IsPublicCheckBox => By.CssSelector("input#isPublic"); + public static By DisplayNameSearchField => By.CssSelector("input#name"); + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddUsersPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddUsersPage.cs new file mode 100644 index 0000000..fac9a50 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AddUsersPage.cs @@ -0,0 +1,30 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AddUsersPage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public AddUsersPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By MailField => By.CssSelector("input#email"); + public static By FirstNameField => By.CssSelector("input#firstName"); + public static By MiddleNamesField => By.CssSelector("input#middleNames"); + public static By LastNameField => By.CssSelector("input#lastName"); + + public static By DisplayNameSearchField => By.CssSelector("input#displayName"); + public static By EmailSearchField => By.CssSelector("input#email"); + public static By DomainNameSearchField => By.CssSelector("input#domainName"); + public static By CreatedSearchField => By.CssSelector("input#created"); + public static By LastUpdatedSearchField => By.CssSelector("input#lastUpdated"); + + // Page actions + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AuditPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AuditPage.cs new file mode 100644 index 0000000..56b3f41 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/AuditPage.cs @@ -0,0 +1,59 @@ +using ESuite.UI.E2E.Helpers; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class AuditPage + { + private readonly IWebDriver driver; + public AuditPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public static By ParentLogButton => By.CssSelector("button .fa-book"); + public static By AllRelatedLogsButton => By.CssSelector("button .fa-book-journal-whills"); + public static By DisplayNameSearchInputField => By.CssSelector("input#displayName"); + public static By LogLines => By.XPath("//div[@class='frame-workArea']/div/table/tbody/tr"); + public static By TypeSearchInputField => By.CssSelector("input#type"); + public static By AuditLogUpdatedValueOfEntity => By.XPath("//table/tbody/tr[1]/td[7]/table/tbody/tr/td[3]"); + public static By AuditLogUpdatedValueOfCustomFieldsEntity => By.XPath("//table/tbody/tr/td[7]/table/tbody/tr/td[3]"); + public static By AuditLogCreatedValueOfEntity => By.XPath("//table/tbody/tr[1]/td[7]/table/tbody/tr/td[2]"); + public static By AuditLogCreatedValueOfCustomFieldsEntity => By.XPath("//table/tbody/tr/td[7]/table/tbody/tr/td[2]"); + public static By AuditLogTypeOfEntity => By.XPath("//table/tbody/tr[1]/td[5]"); + public static By EntityDisplayName => By.XPath("//table/tbody/tr[1]/td[4]"); + public static By CustomFieldsEntityDisplayName => By.XPath("//table/tbody/tr/td[4]"); + public static By TimingDisplay => By.XPath("//table/tbody/tr/td[1]"); + // Page actions + + public static List GetTextFromAuditLog(string logType) + { + IList auditLogValues; + if (logType is "Create" or "Purge") + { + auditLogValues = I.GetTextsFromElements(AuditLogCreatedValueOfEntity, 5); + } + else + { + auditLogValues = I.GetTextsFromElements(AuditLogUpdatedValueOfEntity, 5); + } + return (List)auditLogValues; + } + + public static List GetTextFromAuditLogOnCustomFields(string logType) + { + IList auditLogValues; + if (logType is "Create") + { + auditLogValues = I.GetTextsFromElements(AuditLogCreatedValueOfCustomFieldsEntity, 5); + } + else + { + I.WaitForElementVisibleAndClickable(AuditPage.AllRelatedLogsButton, 5); + auditLogValues = I.GetTextsFromElements(AuditLogUpdatedValueOfCustomFieldsEntity, 5); + } + return [.. auditLogValues]; + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/BasicPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/BasicPage.cs new file mode 100644 index 0000000..3a6e274 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/BasicPage.cs @@ -0,0 +1,93 @@ +using ESuite.UI.E2E.Helpers; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class BasicPage + { + private readonly IWebDriver driver; + + public BasicPage(IWebDriver driver) + { + this.driver = driver; + } + + public IWebDriver Driver => driver; + + // Page elements + public static By NameField => By.CssSelector("input#name"); + public static By SSOProvider => By.Id("ssoProviderId"); + public static By AddressField => By.CssSelector("input#address"); + public static By AddButton => By.XPath("//*[contains(@class,'btn-primary')][text()='Add']"); + public static By SaveAndCloseButton => By.CssSelector("button.btn-primary[name='Save and close']:not([disabled])"); + public static By SaveButton => By.CssSelector("button.btn-primary[name='Submit']:not([disabled])"); + public static By ObjectNameInTable(string? name) => By.XPath($"//table[@class='table table-sm table-striped table-bordered']//*[contains(text(),'{name}')]"); + public static By SearchInput => By.CssSelector("th input#name"); + public static By SearchUsersInput => By.CssSelector("th input#displayName"); + public static By DropdownTab(string title) => By.XPath($"//div[@class='leftMenuItemLabel'][text()='{title}']"); + public static By DropdownOpened(string title) => By.XPath($"//div[@class='leftMenuItemLabel'][text()='{title}']/parent::div[contains(@class,'leftMenuSubMenuOpen')]/ancestor::div[@class='frame-leftMenu']//div[@class='subbar']"); + public static By OpenedDropdown => By.XPath("//div[@class='dropdown-menu show']"); + public static By SelectorByLabel(string? label) => By.XPath($"//label[text()='{label}']/following-sibling::select"); + public static By AlertMessageEmptyFieldByName(string name) => By.XPath($"//div[@class='alert alert-danger'][text()='{name} is not allowed to be empty']"); + public static By LoadingMessage => By.XPath("//div[text()='Loading']"); + public static By AuditObjectButton(string objName) => By.XPath($"//td[text()='{objName}']/following-sibling::td//*[contains(@class, 'fa-book')]"); + public static By EditObjectButton(string objName) => By.XPath($"//td[text()='{objName}']/following-sibling::td//*[contains(@class, 'fa-pen-to-square')]"); + public static By DeleteObjectButton(string objName) => By.XPath($"//td[text()='{objName}']/following-sibling::td//*[contains(@class, 'fa-trash')]"); + public static By DeleteOrganisationButton(string objName) => By.XPath($"//td/a[text()='{objName}']//ancestor::tr/td//*[contains(@class, 'fa-trash')]"); + public static By EditOrganisationButton(string objName) => By.XPath($"//td/a[text()='{objName}']//ancestor::tr/td//*[contains(@class, 'fa-pen-to-square')]"); + public static By EPrintInstanceButton(string objName) => By.XPath($"//td/a[text()='{objName}']"); + public static By OrganisationButton(string objName) => By.XPath($"//td/a[text()='{objName}']"); + public static By ConfirmDeletionButton => By.XPath("//button[text()='Press again to delete']"); + public static By AuditMenuButton => By.XPath("//a[text()='Audit']"); + public static By UserDropdownMenu => By.XPath("//div[contains(@class,'dropdown')]/a[text()='User']"); + public static By UserDropdownMenuItem(string item) => By.XPath($"//div[@class='dropdown-menu show dropdown-menu-end']/a[contains(text(),'{item}')]"); + public static By ToastWithMessage(string text) => By.XPath($"//div[@class='Toastify']//div[text()='{text}']"); + public static By LoadingDropdownMessage => By.XPath("//option[@value='loading...']"); + + // Page actions + + public static void ClickOnDropdownMenuItem(string menuItemName, string menuTitle = "Admin") + { + I.Click(DropdownTab(menuTitle)); + I.WaitForElementVisibleAndClickable(DropdownOpened(menuTitle)); + I.Click(By.XPath($"//div[@class='subbar']/a[text()='{menuItemName}']")); + I.WaitTillInvisible(DropdownOpened(menuTitle)); + } + + public static void SelectTab(string tabName) + { + By locator = By.XPath($"//ul[@class='tab-list']/li[contains(@class, 'tab-list-item')][text()='{tabName}']"); + I.WaitForElementVisibleAndClickable(locator); + I.Click(locator); + } + + // CK-Editor + public static By CKEditorTextBox => By.XPath("//div[contains(@class,'ck-editor__editable')][@role='textbox']"); + public void FillCKEditorTextbox(string text) + { + IWebElement textbox = driver.FindElement(CKEditorTextBox); + textbox.SendKeys(Keys.Control + "a"); + textbox.SendKeys(Keys.Delete); + I.FillField(CKEditorTextBox, text); + } + public static void SearchDeletedObjectNameInTableViaSearchInputField(string name) + { + I.FillField(SearchInput, name); + I.WaitTillInvisible(ObjectNameInTable(name)); + } + + public static void ClickOnDropdownUserMenuItem(string item) + { + I.Click(UserDropdownMenu); + I.Click(UserDropdownMenuItem(item)); + I.WaitTillInvisible(UserDropdownMenuItem(item)); + } + public static void SearchObjectNameInTableViaSearchInputField(string text, By? locator = null) + { + locator ??= SearchInput; // Use SearchInput if no locator is provided + I.Click(locator); + I.FillField(locator, text); + I.WaitForVisible(ObjectNameInTable(text)); + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/DomainEditPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/DomainEditPage.cs new file mode 100644 index 0000000..fdb0454 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/DomainEditPage.cs @@ -0,0 +1,39 @@ +using ESuite.UI.E2E.Helpers; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class DomainEditPage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public DomainEditPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public By EditButton(string? name) => By.XPath($"//td[text()='{name}']/following-sibling::td/a[contains(@class, 'btn-primary')]/*[@data-icon='pen-to-square']"); + public By EditPageTitle => By.XPath("//h1[text()='Edit']"); + public By TemplateNameInList(string? name) => By.XPath($"//ul[@class='mail-types']/li[text()='{name}']"); + + public By RoleAccessCheckbox(string? name) => By.CssSelector($"input#{name}"); + public static By SubjectInput => By.CssSelector("input#subject"); + public By SubjectNameInField(string name) => By.XPath($"//input[@id='subject'][@value='{name}']"); + + public static By AddUserToRoleButton => By.Id("btnAddUserToRole"); + public By MailTemplateFormByName(string name) => By.XPath($"//form[@template-name='{name}']"); + public static By RoleSaveButton => By.XPath("//button[contains(@class, 'btn-primary') and text()='Save']"); + + // Page actions + public void ChooseMailTemplate(string? templateName) + { + By template = TemplateNameInList(templateName); + I.WaitForVisible(template); + I.Click(template); + I.WaitForVisible(MailTemplateFormByName(templateName!.Replace(" ",""))); + } + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/EditUsersPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/EditUsersPage.cs new file mode 100644 index 0000000..8de7a2f --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/EditUsersPage.cs @@ -0,0 +1,26 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class EditUsersPage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public EditUsersPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public By MailField => By.CssSelector("input#email"); + public By FirstNameField => By.CssSelector("input#FirstName"); + public By MiddleNamesField => By.CssSelector("input#MiddleNames"); + public By LastNameField => By.CssSelector("input#LastName"); + public By MFACheckbox => By.CssSelector("#UsingTwoFactorAuthentication"); + public By MFAKey => By.CssSelector(".form-group div label"); + public By MFACodeField => By.CssSelector("#SecurityCode"); + public static By PasswordValidationSuccessString(string text) => By.XPath($"//li[@class='checked'][contains(text(), '{text}')]"); + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/HomePage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/HomePage.cs new file mode 100644 index 0000000..b6fad8c --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/HomePage.cs @@ -0,0 +1,21 @@ +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class HomePage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public HomePage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + + + // Page actions + + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/LoginPage.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/LoginPage.cs new file mode 100644 index 0000000..ca481d4 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/Pages/LoginPage.cs @@ -0,0 +1,60 @@ +using ESuite.UI.E2E.Helpers; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.Pages +{ + public class LoginPage + { + private readonly IWebDriver driver; + + // Constructor to initialize the driver + public LoginPage(IWebDriver driver) + { + this.driver = driver; + } + + // Page elements + public By EmailInput => By.Id("Email"); + public By NextButton => By.XPath("//button[text()='Next']"); + public By PasswordInput => By.Id("Password"); + public static By SecurityCodeInput => By.Id("SecurityCode"); + public By LoginButton => By.XPath("//button[text()='Login']"); + public By ForgottenPasswordButton => By.Id("forgot-password"); + public By ForgottenPasswordMessageAlert => By.XPath("//div[@class='alert alert-info emailSent']"); + public By ConfirmPasswordInput => By.CssSelector("#confirmPasswordDiv .password"); + public By ConfirmEmailButton => By.CssSelector("button[name='confirmEmail']"); + public By SaveButton => By.XPath("//button[@type='submit'][text()='Save']"); + public By ActivateButton => By.XPath("//button[@type='submit'][text()='Activate']"); + public By FormMessage(string text) => By.XPath($"//div[text()='{text}']"); + + // Page actions + public void EnterUserEmail(string username) + { + I.FillField(EmailInput, username); + } + + public void EnterPassword(string password) + { + I.FillField(PasswordInput, password); + } + + public static void Enter2FACode(ScenarioContext scenarioContext) + { + string? code = null; + + RetryHelper.Retry(() => + { + code = AuthenticationHelper.GenerateOTP(scenarioContext["SecretKey"].ToString()!, scenarioContext); + if (string.IsNullOrEmpty(code)) + { + throw new Exception("Generated OTP code is null or empty. Retrying..."); + } + }, 3, 1000); + + if (!string.IsNullOrEmpty(code)) + { + I.FillField(SecurityCodeInput, code); + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/AuditLogsStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/AuditLogsStepDefinitions.cs new file mode 100644 index 0000000..ec3f9df --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/AuditLogsStepDefinitions.cs @@ -0,0 +1,499 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class AuditLogsStepDefinitions + { + private readonly ScenarioContext _scenarioContext; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + private readonly ConfigHelper configHelper; + + public AuditLogsStepDefinitions(ScenarioContext scenarioContext) + { + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + configHelper = new(); + } + /// + /// Step definition for checking Audit logs of a specific object type. + /// + /// The type of object for which Audit logs are being checked. + /// Example: "Forms", "Sequence, "Glossary", "Custom Fields", "Domains", "Users" + /// A table containing the expected Audit log entries. + /// Example: If in column "EntityDisplayName" will be "scenarioDataInstance" + /// we will use data from current scenario instance. + [Then(@"I check (.*) Audit logs")] + public void ThenICheckAuditLogs(string objectType, Table dataTable) + { + + RetryHelper.Retry(() => + { + string objectName; + string? objectTypeCF = null; + var logs = dataTable.CreateSet(); + foreach (var log in logs) + { + switch (log.Type) + { + case "Create": + switch (objectType) + { + case "Forms": + objectName = _scenarioContext["FormName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + break; + case "Sequence": + objectName = _scenarioContext["SequenceName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + CheckAuditLogs(log.Type, objectType, _scenarioContext["SequenceCreated"].ToString()!, true); + break; + case "Glossaries": + objectName = _scenarioContext["GlossaryName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckPartialExistingAuditLogs(log.Type!, objectType, objectName, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + break; + case "Glossary Item": + objectName = _scenarioContext["GlossaryItemName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckPartialExistingAuditLogs(log.Type!, objectType, objectName, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + break; + case "Glossary Custom Field Value": + objectName = _scenarioContext["GlossaryName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type); + CheckPartialExistingAuditLogs(log.Type!, objectType, objectName, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + break; + case "Custom Field": + objectName = _scenarioContext["CustomFieldName"].ToString()!; + objectTypeCF = objectType + " " + _scenarioContext["CustomFieldType"].ToString()!; + CheckCustomFieldsAudits(objectTypeCF, objectName, _scenarioContext["CustomFieldType"].ToString()!, log); + break; + case "Client Domains": + objectName = _scenarioContext["DomainName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainCreated"].ToString()!); + break; + case "Users": + objectName = _scenarioContext["UserName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + //To Do to change from CheckPartialExistingAuditLogsForCustomFields to CheckAuditLogs + CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["UserCreated"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + break; + case "Sso Manager": + objectName = _scenarioContext["SSOProviderName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + CheckAuditLogs(log.Type, objectType, _scenarioContext["SSOProviderCreated"].ToString()!); + break; + case "Organisation": + objectName = _scenarioContext["OrganisationName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckAuditLogs(log.Type, objectType, _scenarioContext["OrganisationCreated"].ToString()!); + break; + case "Site": + objectName = _scenarioContext["SiteName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckAuditLogs(log.Type, objectType, _scenarioContext["SiteCreated"].ToString()!); + break; + case "Role": + objectName = _scenarioContext["DomainRoleName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckAuditLogs(log.Type, objectType, _scenarioContext["RoleCreated"].ToString()!, true); + break; + case "UserRoles": + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type); + CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainRoleName"].ToString()!, true); + break; + case "Role Access": + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type); + CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainRoleName"].ToString()!, true); + break; + case "Mail Template": + objectName = ""; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["DomainMailTemplateCreated"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLog(log.Type)], + () => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable()); + break; + case "Specification": + objectName = _scenarioContext["SpecificationName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["Specification"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLog(log.Type)], + () => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable()); + break; + case "Form Field Instance": + objectName = _scenarioContext["FormFieldInstance"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type); + CheckPartialExistingAuditLogs(log.Type!, objectType, objectName, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + break; + default: + throw new NoSuchElementException($"This type of Log: {objectType} doesn't exist!"); + } + break; + case "Update": + switch (objectType) + { + case "Forms": + //it's for checking version logs registered as create for each version + log.Type = ""; + objectName = _scenarioContext["FormName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + CheckEditedForm(objectName); + break; + case "Sequence": + objectName = _scenarioContext["SequenceName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + CheckAuditLogs(log.Type, objectType, _scenarioContext["SequenceEdited"].ToString()!); + break; + case "Glossary": + objectName = _scenarioContext["GlossaryName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + break; + case "Custom Field": + objectName = _scenarioContext["CustomFieldName"].ToString()!; + objectTypeCF = objectType + " " + _scenarioContext["CustomFieldType"].ToString()!; + CheckCustomFieldsAudits(objectType, objectName, _scenarioContext["CustomFieldType"].ToString()!, log); + break; + case "Client Domains": + objectName = _scenarioContext["DomainName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainEdited"].ToString()!); + break; + case "Users": + objectName = _scenarioContext["UserName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + //To Do to change from CheckPartialExistingAuditLogsForCustomFields to CheckPartialExistingAuditLogs + CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["UserNameEdited"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLog(log.Type)], + () => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable()); + break; + case "Sso Manager": + objectName = _scenarioContext["SSOProviderName"].ToString()!; + CheckAuditOnEntity(objectType, objectName, log); + CheckAuditLogs(log.Type, objectType, _scenarioContext["SSOProviderEdited"].ToString()!); + break; + case "Organisation": + objectName = _scenarioContext["OrganisationName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckAuditLogs(log.Type, objectType, _scenarioContext["OrganisationEdited"].ToString()!); + break; + case "Site": + objectName = _scenarioContext["SiteName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckAuditLogs(log.Type, objectType, _scenarioContext["SiteEdited"].ToString()!); + break; + case "Role": + objectName = _scenarioContext["DomainRoleName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainRoleName"].ToString()!); + break; + case "Mail Template": + objectName = ""; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["DomainMailTemplateUpdated"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLog(log.Type)], + () => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable()); + break; + case "Specification": + objectName = _scenarioContext!["SpecificationName"].ToString()!; + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["SpecificationEdited"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLog(log.Type)], + () => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable()); + break; + case "Form Field Instance": + objectName = _scenarioContext["FormFieldInstance"].ToString()!; + NavigateToAuditLog(); + I.FillField(AuditPage.TypeSearchInputField, log.Type); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + CheckPartialExistingAuditLogs(log.Type!, objectType, objectName, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + break; + default: + throw new NoSuchElementException($"This type of entity: {objectType} doesn't exist!"); + } + break; + case "Delete": + CheckDeletedAuditLog(objectType, GetObjectNameFromScenarioContext(objectType), log); + break; + case "Purge": + CheckPurgedAuditLog(objectType, GetObjectNameFromScenarioContext(objectType), log); + break; + default: + throw new NoSuchElementException($"This type of Log: {log.Type} doesn't exist!"); + + } + } + }); + } + + private string GetObjectNameFromScenarioContext(string objectType) + { + return objectType switch + { + "Forms" => _scenarioContext["FormName"].ToString()!, + "Form Template" => _scenarioContext["FormName"].ToString()!, + "Sequence" => _scenarioContext["SequenceName"].ToString()!, + "Glossary" => _scenarioContext["GlossaryName"].ToString()!, + "Custom Field" => _scenarioContext["CustomFieldName"].ToString()!, + "Client Domains" => _scenarioContext["DomainName"].ToString()!, + "Users" => _scenarioContext["UserName"].ToString()!, + "Sso Manager" => _scenarioContext["SSOProviderName"].ToString()!, + "Organisation" => _scenarioContext["OrganisationName"].ToString()!, + "Site" => _scenarioContext["SiteName"].ToString()!, + "Role" => _scenarioContext["DomainRoleName"].ToString()!, + "Specification" => _scenarioContext["SpecificationName"].ToString()!, + "UserRoles" => _scenarioContext["RoleUserCreated"].ToString()!, + "Custom Field Text" => _scenarioContext["CustomFieldName"].ToString()!, + _ => throw new NoSuchElementException($"This type of entity: {objectType} doesn't exist!") + }; + } + + private void CheckDeletedAuditLog(string objectType, string objectName, AuditData log) + { + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type, objectName); + + var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay); + var expectedTiming = _scenarioContext["Timing"].ToString(); + var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity); + var actualEntityDisplayName = I.GetTextFromElement(AuditPage.EntityDisplayName); + var expectedEntityDisplayName = AutomationTestManagerHelper.AuditEntityDisplayName[objectType]; + + Assert.AreEqual(log.Type, actualLogType, $"Expected log type: {log.Type}, but found: {actualLogType}"); + Assert.AreEqual(expectedEntityDisplayName, actualEntityDisplayName, $"Expected Entity Display Name: {expectedEntityDisplayName}, but found: {actualEntityDisplayName}"); + Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}"); + Assert.IsTrue(I.IsVisibleNumberOfElements(AuditPage.LogLines, 1), "Number of visible log lines doesn't match: 1"); + } + + private void CheckPurgedAuditLog(string objectType, string objectName, AuditData log) + { + NavigateToAuditLog(); + FillAuditLogSearchFields(log.Type); + CheckAuditLogs(log.Type!, objectType, objectName, true); + } + + private static void NavigateToAuditLog() + { + BasicPage.ClickOnDropdownMenuItem("Audit Log", "Support"); + I.WaitForElementVisibleAndClickable(AuditPage.TypeSearchInputField); + } + + private void FillAuditLogSearchFields(string? logType = null, string? objectName = null) + { + if (string.IsNullOrEmpty(objectName)) + { + objectName = ""; + } + + if (string.IsNullOrEmpty(logType)) + { + logType = ""; + } + + I.FillField(AuditPage.DisplayNameSearchInputField, objectName); + Console.WriteLine($"Filling audit log search fields: LogType='{logType}', ObjectName='{objectName ?? ""}'"); + I.FillField(AuditPage.TypeSearchInputField, logType); + + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + } + + public void CheckEditedForm(string objectName) + { + RetryHelper.Retry(() => + { + NavigateToAuditLog(); + I.FillField(AuditPage.DisplayNameSearchInputField, objectName); + int numberOfParentLogs = 1; + int numberOfAllRelatedLogs = (int)_scenarioContext["FormVersion"]!; + int expectedNumberOfAllLogLines = (int)_scenarioContext["FormVersion"]! + numberOfParentLogs; + Assert.IsTrue( + I.IsVisibleNumberOfElements(AuditPage.LogLines, expectedNumberOfAllLogLines), + $"Number of all existing Logs: {numberOfParentLogs} doesn't match number of visible Logs"); + + I.Click(AuditPage.ParentLogButton); + I.WaitTillInvisible(BasicPage.LoadingMessage); + Assert.IsTrue( + I.IsVisibleNumberOfElements(AuditPage.LogLines, numberOfParentLogs), + $"Number of Parent Logs: {numberOfParentLogs} doesn't match number of visible Logs"); + + I.Click(AuditPage.AllRelatedLogsButton); + I.WaitTillInvisible(BasicPage.LoadingMessage); + Assert.IsTrue( + I.IsVisibleNumberOfElements(AuditPage.LogLines, numberOfAllRelatedLogs), + $"Number of all related Logs: {numberOfAllRelatedLogs} doesn't match number of visible Logs"); + }); + } + + public void CheckCustomFieldsAudits(string objectType, string objectName, string? customFieldType, AuditData log) + { + BasicPage.ClickOnDropdownMenuItem("Custom Fields"); + BasicPage.SearchObjectNameInTableViaSearchInputField(objectName); + I.Click(BasicPage.AuditObjectButton(objectName)); + I.WaitTillInvisible(BasicPage.AuditObjectButton(objectName)); + I.WaitForElementVisibleAndClickable(AuditPage.TypeSearchInputField); + I.FillField(AuditPage.TypeSearchInputField, log.Type!); + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + + string auditEntity = customFieldType!.Replace(" ", string.Empty); + if (!string.IsNullOrEmpty(auditEntity) && !auditEntity.Equals("FormTemplate") && !auditEntity.Equals("Domain")) + { + CheckPartialExistingAuditLogs(log.Type!, objectType, _scenarioContext["CustomField"].ToString()!, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + CheckPartialExistingAuditLogs(log.Type!, objectType, auditEntity, + () => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)], + () => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable()); + } + } + + public void CheckCustomFieldsAudits(string objectType, string objectName, AuditData log) + { + CheckCustomFieldsAudits(objectType, objectName, null, log); + } + + public void CheckAuditOnEntity(string objectType, string objectName, AuditData log) + { + NavigateToEntityMenu(objectType); + SearchAuditEntity(objectType, objectName); + OpenAuditLogOnEntity(objectName); + FillAuditLogSearchFields(log.Type, log.DisplayName == "scenarioDataInstance" ? objectName : log.DisplayName); + ValidateAuditLogDetails(log); + } + + private static void NavigateToEntityMenu(string objectType) + { + BasicPage.ClickOnDropdownMenuItem(objectType); + } + + public void CheckAuditLogs(string logType, string entityDisplayName, string auditEntity, bool allowPartialMatch = false) + { + string[] createdData = auditEntity.Split(", "); + string[] auditData = [.. AuditPage.GetTextFromAuditLog(logType)]; + + var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity); + var actualEntityDisplayName = I.GetTextFromElement(AuditPage.EntityDisplayName); + var expectedEntityDisplayName = AutomationTestManagerHelper.AuditEntityDisplayName[entityDisplayName]; + var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay); + var expectedTiming = _scenarioContext["Timing"].ToString()!; + + Assert.AreEqual(logType, actualLogType, $"Expected log type: {logType}, but found: {actualLogType}"); + Assert.AreEqual(expectedEntityDisplayName, actualEntityDisplayName, $"Expected Entity Display Name: {expectedEntityDisplayName}, but found: {actualEntityDisplayName}"); + Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}"); + + if (allowPartialMatch) + { + foreach (string data in createdData) + { + Assert.IsTrue(auditData.Contains(data), $"Expected audit data does not contain: {data}"); + } + } + else + { + Assert.AreEqual(createdData.Length, auditData.Length, $"Expected {createdData.Length} audit entries, but found {auditData.Length}"); + + for (int i = 0; i < createdData.Length; i++) + { + Assert.AreEqual(createdData[i], auditData[i], $"Expected audit data was: '{createdData[i]}', but found '{auditData[i]}'"); + } + } + } + + public void CheckPartialExistingAuditLogs(string logType, string entityDisplayName, string auditEntity, Func getAuditLogFunc, Func> getEntityDisplayNamesFunc) + { + string[] createdData = auditEntity.Split(", "); + string[] auditData = getAuditLogFunc(); + var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity); + var actualDisplayNames = getEntityDisplayNamesFunc(); + var expectedDisplayName = AutomationTestManagerHelper.AuditEntityDisplayName[entityDisplayName]; + var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay); + var expectedTiming = _scenarioContext["Timing"].ToString()!; + + Assert.AreEqual(logType, actualLogType, $"Expected log type: {logType}, but found: {actualLogType}"); + Assert.IsTrue(actualDisplayNames.Any(name => name.Equals(expectedDisplayName)), $"Expected Entity Display Name: {expectedDisplayName}, but found: {string.Join(", ", actualDisplayNames)}"); + Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}"); + + foreach (string data in createdData) + { + Assert.IsTrue(auditData.Any(x => x.Contains(data)), $"Expected audit data does not contain: {data}"); + } + } + private void SearchAuditEntity(string objectType, string objectName) + { + if (objectType.Equals("Users", StringComparison.OrdinalIgnoreCase)) + { + automationTestManagerHelper.SaveDataFromCreatedUser(); + I.WaitForElementVisibleAndClickable(BasicPage.SearchUsersInput); + BasicPage.SearchObjectNameInTableViaSearchInputField(objectName, BasicPage.SearchUsersInput); + I.WaitForVisible(BasicPage.ObjectNameInTable(objectName)); + } + else + { + I.WaitForElementVisibleAndClickable(BasicPage.SearchInput); + BasicPage.SearchObjectNameInTableViaSearchInputField(objectName); + } + } + + private static void OpenAuditLogOnEntity(string objectName) + { + I.Click(BasicPage.AuditObjectButton(objectName)); + I.WaitTillInvisible(BasicPage.AuditObjectButton(objectName)); + I.WaitForElementVisibleAndClickable(AuditPage.TypeSearchInputField); + } + + private void ValidateAuditLogDetails(AuditData log) + { + I.Click(AuditPage.ParentLogButton); + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + + var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay); + var expectedTiming = _scenarioContext["Timing"].ToString()!; + var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity); + + if (log.Type!.Equals("Create", StringComparison.OrdinalIgnoreCase)) + { + Assert.IsTrue( + I.IsVisibleNumberOfElements(AuditPage.LogLines, 1), + "Number of the Log Lines wasn't equal to 1" + ); + Assert.AreEqual(log.Type!, actualLogType, $"Expected log type: {log.Type!}, but found: {actualLogType}"); + } + + Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}"); + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/CustomFieldsStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/CustomFieldsStepDefinitions.cs new file mode 100644 index 0000000..1ecb41d --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/CustomFieldsStepDefinitions.cs @@ -0,0 +1,277 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class CustomFieldsStepDefinitions + { + private readonly ScenarioContext _scenarioContext; + private readonly ConfigHelper configHelper; + public CustomFieldsStepDefinitions(ScenarioContext scenarioContext) + { + _scenarioContext = scenarioContext; + configHelper = new(); + } + + [Given(@"^I (create|edit) a CustomField$")] + [When(@"^I (create|edit) a CustomField$")] + public void WhenICreateACustomFieldWith(string action, Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Custom Fields"); + + var customFields = dataTable.CreateSet(); + + foreach (var customField in customFields) + { + if (action == "create") + { + _scenarioContext["CustomFieldName"] = customField.Name + _scenarioContext["GUIDPostfix"]; + + I.Click(BasicPage.AddButton); + } + else if (action == "edit") + { + I.WaitForElementVisibleAndClickable(BasicPage.SearchInput); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["CustomFieldName"].ToString()!); + I.Click(BasicPage.EditObjectButton(_scenarioContext["CustomFieldName"].ToString()!)); + _scenarioContext["CustomFieldName"] = customField.Name + _scenarioContext["GUIDPostfix"]; + } + I.WaitForPageToLoad(); + + if (!string.IsNullOrEmpty(customField.Name)) + { + I.WaitForElementVisibleAndClickable(BasicPage.NameField); + I.FillField(BasicPage.NameField, _scenarioContext["CustomFieldName"].ToString()!); + } + if (customField.FieldType != null) I.SelectOption(AddCustomFieldsPage.FieldTypeSelector, customField.FieldType!); + By selector = BasicPage.SelectorByLabel(customField.FieldType); + + //Thread.Sleep(3000); + switch (customField.FieldType) + { + case "Sequence": + I.WaitForVisible(selector); + if (customField.Sequence != null) I.SelectOption(selector, _scenarioContext["SequenceName"]!); + _scenarioContext["CustomField"] = $"{_scenarioContext["CustomFieldName"]}, {customField.FieldType.Trim()}"; + _scenarioContext["CustomFieldNameSequence"] = $"{_scenarioContext["CustomFieldName"]}"; + break; + case "Glossary": + I.WaitForVisible(selector); + if (customField.Glossary != null) I.SelectOption(selector, _scenarioContext["GlossaryName"]!); + if (customField.Required != null && customField.Required.Equals("true", StringComparison.CurrentCultureIgnoreCase) && !(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + _scenarioContext["CustomFieldRequired"] = $"{customField.Required}"; + } + else if (customField.Required != null && customField.Required.Equals("false", StringComparison.CurrentCultureIgnoreCase) && (I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + _scenarioContext["CustomFieldRequired"] = $"{customField.Required}"; + } + if (customField.MaxEntries != null) + { + I.FillField(AddCustomFieldsPage.MaxEntriesField, customField.MaxEntries); + _scenarioContext["CustomFieldMaxEntries"] = $"{customField.MaxEntries}"; + } + else if (customField.MaxEntries == null) + { + I.FillField(AddCustomFieldsPage.MaxEntriesField, ""); + _scenarioContext["CustomFieldMaxEntries"] = $"{""}"; + } + _scenarioContext["CustomField"] = $"{_scenarioContext["CustomFieldName"]}, {customField.FieldType.Trim()}, {_scenarioContext["CustomFieldMaxEntries"]}"; + _scenarioContext["CustomFieldNameGlossary"] = $"{_scenarioContext["CustomFieldName"]}"; + + break; + case "Form Template": + _scenarioContext["CustomField"] = $"{_scenarioContext["CustomFieldName"]}"; + _scenarioContext["CustomFieldNameFormTemplate"] = $"{_scenarioContext["CustomFieldName"]}"; + break; + case "Number": + if (customField.DefaultValue != null) + { + I.FillField(AddCustomFieldsPage.DefaultValueField, customField.DefaultValue); + _scenarioContext["CustomFieldDefaultValue"] = $"{customField.DefaultValue}"; + } + if (customField.MinimumValue != null) + { + I.FillField(AddCustomFieldsPage.MinValueField, customField.MinimumValue); + _scenarioContext["CustomFieldMinimumValue"] = $"{customField.MinimumValue}"; + } + if (customField.MaximumValue != null) + { + I.FillField(AddCustomFieldsPage.MaxValueField, customField.MaximumValue); + _scenarioContext["CustomFieldMaximumValue"] = $"{customField.MaximumValue}"; + } + if (customField.Step != null) + { + I.FillField(AddCustomFieldsPage.StepField, customField.Step); + _scenarioContext["CustomFieldStep"] = $"{customField.Step}"; + } + if (customField.Required != null && customField.Required.Equals("true", StringComparison.CurrentCultureIgnoreCase) && !(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + _scenarioContext["CustomFieldRequired"] = $"{customField.Required}"; + + } + else if (customField.Required != null && customField.Required.Equals("false", StringComparison.CurrentCultureIgnoreCase) && (I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + _scenarioContext["CustomFieldRequired"] = $"{customField.Required}"; + } + _scenarioContext["CustomField"] = $"{_scenarioContext["CustomFieldName"]}, {customField.DefaultValue}, {customField.FieldType}, {customField.MinimumValue}, {customField.MaximumValue}, {customField.Step}"; + _scenarioContext["CustomFieldNameNumber"] = $"{_scenarioContext["CustomFieldName"]}"; + break; + case "Text": + if (customField.DefaultValue != null) I.FillField(AddCustomFieldsPage.DefaultValueField, customField.DefaultValue); + if (customField.MultiLine != null && customField.MultiLine.Equals("true", StringComparison.CurrentCultureIgnoreCase) && !(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + } + else if (customField.MultiLine != null && customField.MultiLine.Equals("false", StringComparison.CurrentCultureIgnoreCase) && (I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + } + _scenarioContext["CustomFieldDefaultValue"] = $"{customField.DefaultValue}"; + _scenarioContext["CustomFieldMultiLine"] = $"{customField.MultiLine}"; + _scenarioContext["CustomField"] = $"{_scenarioContext["CustomFieldName"]}, {customField.DefaultValue}, {customField.MultiLine}"; + _scenarioContext["CustomFieldNameText"] = $"{_scenarioContext["CustomFieldName"]}"; + break; + case "Domain": + if (customField.MaxEntries != null) + { + I.FillField(AddCustomFieldsPage.MaxEntriesField, customField.MaxEntries); + _scenarioContext["CustomFieldMaxEntries"] = $"{customField.MaxEntries}"; + } + if (customField.Required != null && customField.Required.Equals("true", StringComparison.CurrentCultureIgnoreCase) && !(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + _scenarioContext["CustomFieldRequired"] = $"{customField.Required}"; + } + else if (customField.Required != null && customField.Required.Equals("false", StringComparison.CurrentCultureIgnoreCase) && (I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1))) + { + I.Click(AddCustomFieldsPage.CheckBox); + _scenarioContext["CustomFieldRequired"] = $"{customField.Required}"; + } + _scenarioContext["CustomField"] = $"{_scenarioContext["CustomFieldName"]}, {customField.MaxEntries}"; + _scenarioContext["CustomFieldNameDomain"] = $"{_scenarioContext["CustomFieldName"]}"; + break; + + default: + throw new NoSuchElementException($"This type of Custom Field: {customField.FieldType} doesn't exist!"); + } + _scenarioContext["CustomFieldType"] = customField.FieldType; + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.ClickOnDropdownMenuItem("Custom Fields"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["CustomFieldName"].ToString()!); + } + } + + [AfterScenario("deletecustomfield", Order = 90)] + [When(@"I delete a CustomField")] + public void WhenIDeleteACustomField() + { + BasicPage.ClickOnDropdownMenuItem("Custom Fields"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["CustomFieldName"].ToString()!); + I.Click(BasicPage.DeleteObjectButton(_scenarioContext["CustomFieldName"].ToString()!)); + I.WaitTillInvisible(BasicPage.DeleteObjectButton(_scenarioContext["CustomFieldName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.ConfirmDeletionButton); + } + + [Then(@"I check data on Custom Field page")] + public void ThenICheckDataOnCustomFieldPage(Table dataTable) + { + var customFields = dataTable.CreateSet(); + RetryHelper.Retry(() => + { + BasicPage.ClickOnDropdownMenuItem("Custom Fields"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["CustomFieldName"].ToString()!, AddSsoProvider.DisplayNameSearchField); + + I.Click(BasicPage.EditObjectButton(_scenarioContext["CustomFieldName"].ToString()!)); + I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext["CustomFieldName"].ToString()!)); + I.WaitForPageToLoad(); + + foreach (var customField in customFields) + { + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + I.WaitForElementWithAttributeValue(BasicPage.NameField, "value", _scenarioContext["CustomFieldName"].ToString()!); + var expectedCustomFieldType = _scenarioContext["CustomFieldType"].ToString()!; + var actualCustomFieldType = I.ReturnSelectedOption(AddCustomFieldsPage.FieldTypeSelector, 1); + + Assert.AreEqual(expectedCustomFieldType, actualCustomFieldType, $"Expected Custom Field Type was: {expectedCustomFieldType}, but found: {actualCustomFieldType}"); + By selector = BasicPage.SelectorByLabel(customField.FieldType); + switch (customField.FieldType) + { + case "Sequence": + var expectedSequence = _scenarioContext["SequenceName"].ToString()!; + var actualSequence = I.ReturnSelectedOption(selector, 1); + Assert.AreEqual(expectedSequence, actualSequence, $"Expected Sequence value was: {expectedSequence}, but found: {actualSequence}"); + break; + case "Glossary": + var expectedGlossary = _scenarioContext["GlossaryName"].ToString()!; + var actualGlossary = I.ReturnSelectedOption(selector, 1); + Assert.AreEqual(expectedGlossary, actualGlossary, $"Expected Glossary value was: {expectedGlossary}, but found: {actualGlossary}"); + if (_scenarioContext["CustomFieldRequired"].ToString()!.Equals("true")) + { + Assert.IsTrue(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field required option is not selected"); + } + else + { + Assert.IsFalse(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field required option is selected"); + } + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.MaxEntriesField, "value", _scenarioContext["CustomFieldMaxEntries"].ToString()!); + break; + case "Form Template": + break; + case "Number": + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.MinValueField, "value", _scenarioContext["CustomFieldMinimumValue"].ToString()!); + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.MaxValueField, "value", _scenarioContext["CustomFieldMaximumValue"].ToString()!); + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.StepField, "value", _scenarioContext["CustomFieldStep"].ToString()!); + if (_scenarioContext["CustomFieldRequired"].ToString()!.Equals("true")) + { + Assert.IsTrue(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field required option is not selected"); + } + else + { + Assert.IsFalse(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field required option is selected"); + } + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.DefaultValueField, "value", _scenarioContext["CustomFieldDefaultValue"].ToString()!); + break; + case "Text": + if (_scenarioContext["CustomFieldMultiLine"].ToString()!.Equals("true")) + { + Assert.IsTrue(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field multiline option is not selected"); + } + else + { + Assert.IsFalse(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field multiline option is selected"); + } + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.DefaultValueField, "value", _scenarioContext["CustomFieldDefaultValue"].ToString()!); + break; + case "Domain": + if (_scenarioContext["CustomFieldRequired"].ToString()!.Equals("true")) + { + Assert.IsTrue(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field required option is not selected"); + } + else + { + Assert.IsFalse(I.WaitForElementToBeChecked(AddCustomFieldsPage.CheckBox, 1), "Custom Field required option is selected"); + } + I.WaitForElementWithAttributeValue(AddCustomFieldsPage.MaxEntriesField, "value", _scenarioContext["CustomFieldMaxEntries"].ToString()!); + break; + default: + throw new NoSuchElementException($"This type of Custom Field: {customField} doesn't exist!"); + } + } + }); + } + } + +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/DomainCreationStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/DomainCreationStepDefinitions.cs new file mode 100644 index 0000000..ec86f4d --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/DomainCreationStepDefinitions.cs @@ -0,0 +1,307 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class DomainCreationStepDefinitions + { + private readonly IWebDriver driver; + private readonly BasicPage basicPage; + private readonly DomainEditPage domainEditPage; + private readonly ScenarioContext _scenarioContext; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + private readonly APIHelper apiHelper; + private readonly ConfigHelper configHelper; + + public DomainCreationStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + basicPage = new(driver); + domainEditPage = new(driver); + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + apiHelper = new(_scenarioContext); + configHelper = new(); + } + + [AfterScenario("deletedomain", Order = 10)] + [When(@"I delete existing Domain")] + public void DeleteDomain() + { + automationTestManagerHelper.DeleteDomain(); + } + + [AfterScenario("deletedomainapi", Order = 10)] + [When(@"I delete existing Domain via API")] + public async Task DeleteDomainViaAPI() + { + await automationTestManagerHelper.DeleteDomainAPI(); + } + + [BeforeScenario("createdomain", Order = 15)] + public async Task CreateDomain() + { + await automationTestManagerHelper.CreateDomain(""); + var domains = await apiHelper.GetDomains(configHelper.APIUrl); + var data = domains["data"]!.ElementAt(0); + int domainId = (int)data["id"]!; + string domainName = (string)data["name"]!; + Guid domainGuid = Guid.Parse((string)data["guid"]!); + Assert.AreEqual(domainName, _scenarioContext["DomainName"].ToString()!); + _scenarioContext["DomainId"] = domainId; + _scenarioContext["DomainGUID"] = domainGuid; + } + + [Given(@"I create a new domain via API")] + public async Task CreateDomain(Table dataTable) + { + var domains = dataTable.CreateSet(); + List domainList = []; + foreach (var domain in domains) + { + var domainName = domain.Name + _scenarioContext["GUID"]; + + await automationTestManagerHelper.CreateDomain(domainName); + domainList.Add(domainName); + } + _scenarioContext["DomainList"] = domainList; + } + + [Given(@"I create a new domain")] + public void GivenICreateANewDomain(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Client Domains"); + + var domains = dataTable.CreateSet(); + + foreach (var domain in domains) + { + _scenarioContext["DomainName"] = domain.Name + _scenarioContext["GUIDPostfix"]; + + I.Click(BasicPage.AddButton); + I.FillField(BasicPage.NameField, _scenarioContext["DomainName"].ToString()!); + if (!string.IsNullOrWhiteSpace(domain.SSOProvider)) + { + I.SelectOption(BasicPage.SSOProvider, _scenarioContext["SSOProviderName"].ToString()!); + } + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainName"].ToString()!); + } + } + + [When(@"I edit domains details")] + public void WhenIEditDomainsDetails(Table dataTable) + { + var domains = dataTable.CreateSet(); + + foreach (var domain in domains) + { + _scenarioContext["DomainName"] = domain.Name + _scenarioContext["GUIDPostfix"]; + + I.FillField(BasicPage.NameField, _scenarioContext["DomainName"].ToString()!); + if (!string.IsNullOrWhiteSpace(domain.SSOProvider)) + { + I.SelectOption(BasicPage.SSOProvider, _scenarioContext["SSOProviderName"].ToString()!); + } + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainName"].ToString()!); + } + _scenarioContext["DomainEdited"] = $"{_scenarioContext["DomainName"]}, {_scenarioContext["SSOProviderName"]}"; + } + + [Given(@"I edit created domain")] + [When(@"I edit created domain")] + public void WhenIEditCreatedDomain() + { + BasicPage.ClickOnDropdownMenuItem("Client Domains"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainName"].ToString()!); + I.Click(domainEditPage.EditButton(_scenarioContext["DomainName"].ToString())); + I.WaitForVisible(domainEditPage.EditPageTitle); + } + + [Then(@"I add a new Security Role")] + public void ThenIAddANewSecurityRole(Table dataTable) + { + var roles = dataTable.CreateSet(); + foreach (var role in roles) + { + _scenarioContext["DomainRoleName"] = role.RoleName + _scenarioContext["GUIDPostfix"]; + + BasicPage.SelectTab("Security Roles"); + + I.Click(BasicPage.AddButton); + I.FillField(BasicPage.NameField, _scenarioContext["DomainRoleName"].ToString()!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + BasicPage.SelectTab("Security Roles"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainRoleName"].ToString()!); + } + } + + [Then(@"I change Mail Template")] + public void ThenIChangeMailTemplate(Table dataTable) + { + var templates = dataTable.CreateSet(); + foreach (var template in templates) + { + _scenarioContext["DomainMailTemplateName"] = template.TemplateName; + _scenarioContext["DomainMailTemplateSubject"] = template.Subject + _scenarioContext["GUIDPostfix"]; + _scenarioContext["DomainMailTemplateDefinition"] = template.Definition + _scenarioContext["GUIDPostfix"]; + _scenarioContext["DomainMailTemplateCreated"] = $"{"false"}, {_scenarioContext["DomainName"]}, {_scenarioContext["DomainMailTemplateName"]}, " + + $"{_scenarioContext["DomainMailTemplateSubject"]}"; + _scenarioContext["DomainMailTemplateUpdated"] = $"{_scenarioContext["DomainMailTemplateSubject"]}, {_scenarioContext["DomainMailTemplateDefinition"]}"; + BasicPage.SelectTab("Mail Templates"); + I.WaitForPageToLoad(); + domainEditPage.ChooseMailTemplate(_scenarioContext["DomainMailTemplateName"].ToString()); + I.WaitForElementVisibleAndClickable(DomainEditPage.SubjectInput); + I.FillField(DomainEditPage.SubjectInput, _scenarioContext["DomainMailTemplateSubject"].ToString()!); + if (I.GetValueAttribute(DomainEditPage.SubjectInput) != _scenarioContext["DomainMailTemplateSubject"].ToString()) + { + I.FillField(DomainEditPage.SubjectInput, _scenarioContext["DomainMailTemplateSubject"].ToString()!); + } + I.FillField(BasicPage.CKEditorTextBox, _scenarioContext["DomainMailTemplateDefinition"].ToString()!); + + _scenarioContext["CKEditorTextBoxContent"] = I.GetTextFromElement(BasicPage.CKEditorTextBox); + + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + } + } + + [When(@"I check Mail Template changes")] + public void ThenICheckMailTemplateChanges() + { + RetryHelper.Retry(() => + { + BasicPage.SelectTab("Mail Templates"); + domainEditPage.ChooseMailTemplate(_scenarioContext["DomainMailTemplateName"].ToString()); + I.WaitForVisible(domainEditPage.SubjectNameInField(_scenarioContext["DomainMailTemplateSubject"].ToString()!)); + Assert.AreEqual( + I.GetValueAttribute(DomainEditPage.SubjectInput), + _scenarioContext["DomainMailTemplateSubject"] + ); + Assert.AreEqual( + _scenarioContext["CKEditorTextBoxContent"], + I.GetTextFromElement(BasicPage.CKEditorTextBox) + ); + }); + } + + [Then(@"I check new Security Role created")] + public void ThenICheckNewSecurityRoleCreated() + { + RetryHelper.Retry(() => + { + BasicPage.SelectTab("Security Roles"); + I.WaitForPageToLoad(); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainRoleName"].ToString()!); + }); + } + + [When(@"I click on newly created Security Role")] + public void WhenIClickOnNewlyCreatedSecurityRole() + { + I.Click(BasicPage.ObjectNameInTable(_scenarioContext["DomainRoleName"].ToString())); + I.WaitForPageToLoad(); + } + + [Then(@"I choose Role Access permission options")] + public void ThenIChooseRoleAccessPermissionOptions(Table dataTable) + { + var permissions = dataTable.CreateSet(); + foreach (var permission in permissions) + { + if (!string.IsNullOrEmpty(permission.Name)) + { + I.Click(domainEditPage.RoleAccessCheckbox( + permission.Name.Replace(" ", "") + ) + ); + } + } + I.Click(DomainEditPage.RoleSaveButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + + [When(@"I enter into Users tab")] + public void WhenIEnterIntoUsersTab() + { + BasicPage.SelectTab("Users"); + } + + [Then(@"I add User to Security Role")] + public void ThenIAddUserToSecurityRole(Table dataTable) + { + By UserSelector = BasicPage.SelectorByLabel("User"); + var users = dataTable.CreateSet(); + + foreach (var user in users) + { + if (!user.UserName!.Equals("UserName")) + { + _scenarioContext["UserName"] = user.UserName; + } + + I.Click(DomainEditPage.AddUserToRoleButton); + I.WaitForVisible(UserSelector); + I.SelectOption(UserSelector, _scenarioContext["UserName"]!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + _scenarioContext["RoleUserCreated"] = $"{"false"}, {_scenarioContext["DomainRoleName"]}, {_scenarioContext["UserName"]}"; + } + + [Then(@"I check if user is added to Security Role")] + public void ThenICheckIfUserIsAddedToSecurityRole() + { + RetryHelper.Retry(() => + { + I.FillField(BasicPage.SearchUsersInput, _scenarioContext["UserName"].ToString()!); + I.WaitForVisible(BasicPage.ObjectNameInTable(_scenarioContext["UserName"].ToString())); + }); + } + + [Given(@"I add a new Security Role via API")] + public void GivenCreateRole() + { + automationTestManagerHelper.CreateRole(); + } + + [Then(@"I delete added Security Role")] + [When(@"I delete added Security Role")] + public void ThenIDeleteAddedSecurityRole() + { + BasicPage.ClickOnDropdownMenuItem("Client Domains"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainName"].ToString()!); + I.Click(domainEditPage.EditButton(_scenarioContext["DomainName"].ToString())); + BasicPage.SelectTab("Security Roles"); + I.Click(BasicPage.DeleteObjectButton(_scenarioContext["DomainRoleName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + + [When(@"I delete added User from Security Role")] + public void ThenIDeleteUserFromSecurityRole() + { + BasicPage.ClickOnDropdownMenuItem("Client Domains"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["DomainName"].ToString()!); + I.Click(domainEditPage.EditButton(_scenarioContext["DomainName"].ToString())); + BasicPage.SelectTab("Security Roles"); + I.Click(BasicPage.ObjectNameInTable(_scenarioContext["DomainRoleName"].ToString())); + BasicPage.SelectTab("Users"); + I.FillField(BasicPage.SearchUsersInput, _scenarioContext["UserName"].ToString()!); + I.Click(BasicPage.DeleteObjectButton(_scenarioContext["UserName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/ErrorLogsVerificationStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/ErrorLogsVerificationStepDefinitions.cs new file mode 100644 index 0000000..cbb7d93 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/ErrorLogsVerificationStepDefinitions.cs @@ -0,0 +1,69 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class ErrorLogsVerificationStepDefinitions + { + + private readonly IWebDriver driver; + private readonly BasicPage basicPage; + private readonly ScenarioContext _scenarioContext; + private readonly APIHelper apiHelper; + private readonly ConfigHelper configHelper; + public ErrorLogsVerificationStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + basicPage = new BasicPage(driver); + _scenarioContext = scenarioContext; + apiHelper = new APIHelper(_scenarioContext); + configHelper = new ConfigHelper(); + } + + [Given(@"I create a new domain with insufficient info via API call")] + public async Task GivenICreateANewDomainWithInsufficientInfoViaAPICall() + { + int maxAttempts = 2; + int currentAttempt = 0; + string content; + HttpResponseMessage? response; + + do + { + string token = await apiHelper.GetAuthToken(); + string url = $"{configHelper.APIUrl}/api/Domain/domain"; + string payload = $@" + {{ + ""name"": 123, + ""guid"": ""3fa85f64-5717-4562-b3fc-2c963f66afa6"" + }}"; // Bad Payload. Backend expects to get 'name' in string format. + + response = await apiHelper.SendAuthenticatedRequest(url, token, payload, "POST"); + content = await response.Content.ReadAsStringAsync(); + if (!string.IsNullOrEmpty(content)) + { + string instanceID = APIHelper.GetFieldValueFromJSONResponse("Instance", content); + _scenarioContext["ErrorInstanceID"] = instanceID; + break; + } + + currentAttempt++; + } while (currentAttempt < maxAttempts); + + if (string.IsNullOrEmpty(content)) + { + throw new Exception($"Failed to get a valid response after {currentAttempt} attempts."); + } + } + + [Then(@"I verifying newly created exception on the Error Logs page")] + public void ThenIVerifyingNewlyCreatedExceptionOnTheErrorLogsPage() + { + BasicPage.ClickOnDropdownMenuItem("Error Logs", "Support"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["ErrorInstanceID"].ToString()!,By.Id("id")); + } + + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/GlossaryObjectsStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/GlossaryObjectsStepDefinitions.cs new file mode 100644 index 0000000..f9dd8ae --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/GlossaryObjectsStepDefinitions.cs @@ -0,0 +1,215 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class GlossaryObjectsStepDefinitions + { + private readonly IWebDriver driver; + private readonly ScenarioContext _scenarioContext; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + + public GlossaryObjectsStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + } + + [When(@"^I (create|edit) a FormTemplate$")] + [Given(@"^I (create|edit) a FormTemplate$")] + public void WhenICreateAFormTemplate(string action, Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Forms"); + + var forms = dataTable.CreateSet(); + + if (action == "create") + { + I.Click(BasicPage.AddButton); + foreach (var form in forms) + { + FillFormTemplate(form); + } + } + else if (action == "edit") + { + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["FormName"].ToString()!); + I.Click(BasicPage.EditObjectButton(_scenarioContext["FormName"].ToString()!)); + foreach (var form in forms) + { + FillFormTemplate(form); + } + } + + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.ClickOnDropdownMenuItem("Forms"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["FormName"].ToString()!); + + } + + [When(@"I create a Glossary")] + [Given(@"I create a Glossary")] + public void ThenICreateAGlossaryWithSequenceCustomField(Table dataTable) + { + var glossaries = dataTable.CreateSet(); + BasicPage.ClickOnDropdownMenuItem("Glossaries"); + + I.Click(BasicPage.AddButton); + foreach (var glossary in glossaries) + { + switch (glossary.Add) + { + case "customField": + I.Click(AddGlossariesPage.CustomFieldsSelector); + I.SelectOption(AddGlossariesPage.CustomFieldsSelector, _scenarioContext["CustomFieldName"]!); + break; + case "form": + I.Click(AddGlossariesPage.CustomFieldsSelector); + I.SelectOption(AddGlossariesPage.CustomFieldsSelector, _scenarioContext["CustomFieldName"]!); + break; + default: + break; + } + + if (!string.IsNullOrEmpty(glossary.Name)) + { + _scenarioContext["GlossaryName"] = glossary.Name + _scenarioContext["GUIDPostfix"]; + + I.Click(BasicPage.NameField); + I.FillField(BasicPage.NameField, _scenarioContext["GlossaryName"].ToString()!); + } + + if (!string.IsNullOrEmpty(glossary.Add)) + { + + I.Click(AddGlossariesPage.PlusButton); + I.WaitTillInvisible(AddGlossariesPage.PlusButton); + } + } + + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.ClickOnDropdownMenuItem("Glossaries"); + I.WaitForVisible(AddGlossariesPage.SearchGlossaryNameInTable(_scenarioContext["GlossaryName"].ToString())); + } + + [Then(@"I create a Glossary Item")] + [Given(@"I create a Glossary Item")] + public void ThenICreateAGlossaryItem(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Glossaries"); + + var items = dataTable.CreateSet(); + List glossaryList = []; + + foreach (var item in items) + { + _scenarioContext["GlossaryItemName"] = item.Name + Guid.NewGuid(); + I.Click(By.LinkText(_scenarioContext["GlossaryName"].ToString()!)); + I.Click(BasicPage.AddButton); + I.WaitTillInvisible(BasicPage.LoadingMessage); + + if (_scenarioContext.TryGetValue("FormName", out object? value)) + { + try + { + I.FillField(BasicPage.NameField, _scenarioContext["CustomFieldName"].ToString()!); + I.SelectOption( + BasicPage.SelectorByLabel(_scenarioContext["CustomFieldName"].ToString()), value!); + } + catch (Exception) + { + I.RefreshPage(driver); + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.FillField(BasicPage.NameField, _scenarioContext["CustomFieldName"].ToString()!); + I.SelectOption( + BasicPage.SelectorByLabel(_scenarioContext["CustomFieldName"].ToString()), value!); + } + } + else if (!string.IsNullOrEmpty(item.CustomField)) + { + I.SelectOption(AddGlossaryItemPage.AddSelector, _scenarioContext["CustomFieldName"]!); + } + + I.FillField(BasicPage.NameField, _scenarioContext["GlossaryItemName"].ToString()!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + I.WaitForVisible(AddGlossariesPage.SearchGlossaryNameInTable(_scenarioContext["GlossaryItemName"].ToString())); + glossaryList.Add(_scenarioContext["GlossaryItemName"].ToString()!); + } + _scenarioContext["GlossaryList"] = glossaryList; + } + + [Then(@"I check if version of FormTemplate was changed")] + [Then(@"I check if version of FormTemplate version is correct")] + public void ThenICheckIfVersionOfFormTemplateWasChanged(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Forms"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["FormName"].ToString()!); + + var versions = dataTable.CreateSet(); + + foreach (var version in versions) + { + int actualVersion = AddFormTemplatePage.GetFormVersionTemplateByName(_scenarioContext["FormName"].ToString()!); + + _scenarioContext["FormVersion"] = version.Version; + + Assert.AreEqual((int)_scenarioContext["FormVersion"], actualVersion); + } + } + + [AfterScenario("deleteform", Order = 5)] + [When(@"I delete existing Form Template")] + [Then(@"I delete existing Form Template")] + public void DeleteFormTemplate() + { + automationTestManagerHelper.DeleteFormTemplate(); + } + + private void FillFormTemplate(FormTemplateData form) + { + if (!string.IsNullOrEmpty(form.Name)) _scenarioContext["FormName"] = form.Name + _scenarioContext["GUIDPostfix"]; + if (!string.IsNullOrEmpty(form.ChildFormName)) _scenarioContext["ChildFormName"] = $"{_scenarioContext["FormName"]}"; + if (!string.IsNullOrEmpty(form.Name)) I.FillField(BasicPage.NameField, _scenarioContext["FormName"].ToString()!); + if (form.NeedTable == true) AddFormTemplatePage.CreateTableViaGrid(form.TotalNumberOfRows, form.TotalNumberOfColumns); + if (!string.IsNullOrEmpty(form.Text)) AddFormTemplatePage.FillFieldTextInForm(form.Text, form.RowNumber, form.ColumnNumber); + switch (form.CustomFields) + { + case "customFieldNameFromScenarioContext": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldName"].ToString(), form.RowNumber, form.ColumnNumber); + break; + case "Glossary": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldNameGlossary"].ToString(), form.RowNumber, form.ColumnNumber); + break; + case "Domain": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldNameDomain"].ToString(), form.RowNumber, form.ColumnNumber); + break; + case "Text": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldNameText"].ToString(), form.RowNumber, form.ColumnNumber); + break; + case "Sequence": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldNameSequence"].ToString(), form.RowNumber, form.ColumnNumber); + break; + case "Form Template": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldNameFormTemplate"].ToString(), form.RowNumber, form.ColumnNumber); + break; + case "Number": + AddFormTemplatePage.ChooseCustomField(_scenarioContext["CustomFieldNameNumber"].ToString(), form.RowNumber, form.ColumnNumber); + break; + default: + break; + } + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/MailCheckStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/MailCheckStepDefinitions.cs new file mode 100644 index 0000000..bd638ee --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/MailCheckStepDefinitions.cs @@ -0,0 +1,47 @@ +using ESuite.UI.E2E.Helpers; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class MailCheckStepDefinitions + { + private readonly ScenarioContext _scenarioContext; + private readonly APIHelper apiHelper; + private readonly ConfigHelper configHelper; + + public MailCheckStepDefinitions(ScenarioContext scenarioContext) + { + _scenarioContext = scenarioContext; + apiHelper = new APIHelper(_scenarioContext); + configHelper = new ConfigHelper(); + } + + [When(@"I click on the Link in the sent email")] + public async Task WhenIClickOnTheLinkInTheSentEmail() + { + var token = await apiHelper.GetAuthToken(); + string url = GetUrl("ConfirmEmailAddress"); + string confirmationLink = await apiHelper.SendAuthenticatedRequest(url, token); + I.NavigateToURL(confirmationLink); + } + + [When(@"I click on the Link in the reset password email")] + public async Task WhenIClickOnTheLinkInTheResetPasswordEmail() + { + var token = await apiHelper.GetAuthToken(); + string url = GetUrl("PasswordReset"); + string confirmationLink = await apiHelper.SendAuthenticatedRequest(url, token); + + I.NavigateToURL(confirmationLink); + } + + private string GetUrl(string emailUserActionType) + { + var uriBuilder = new UriBuilder($"{configHelper.APIUrl}/api/User/currentEmailUserActionUrl") + { + Query = $"emailAddress={_scenarioContext["UserEmail"]}&emailUserActionType={emailUserActionType}" + }; + return uriBuilder.ToString(); + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/OrganisationCreationStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/OrganisationCreationStepDefinitions.cs new file mode 100644 index 0000000..93a3b8b --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/OrganisationCreationStepDefinitions.cs @@ -0,0 +1,143 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class OrganisationCreationStepDefinitions + { + private readonly ScenarioContext _scenarioContext; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + public OrganisationCreationStepDefinitions(ScenarioContext scenarioContext) + { + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + } + + [BeforeScenario("createorganisation", Order = 10)] + public async Task CreateOrganisation() + { + await automationTestManagerHelper.CreateOrganisation(); + } + + [BeforeScenario("createorganisation_site", Order = 11)] + public void CreateOrganisationAndLinkedSite() + { + //this request triggers create organisation request + CreateOrganisation().GetAwaiter().GetResult(); + + automationTestManagerHelper.CreateSite(); + } + + [BeforeScenario("createsite", Order = 12)] + public void CreateSite() + { + automationTestManagerHelper.CreateSite(); + } + + [AfterScenario("deleteorganisation", Order = 99)] + [When(@"I delete existing Organisation")] + public void DeleteOrganisation() + { + automationTestManagerHelper.DeleteOrganisation(); + } + + [Given(@"I create a new organisation")] + public void GivenICreateANewOrganisation(Table dataTable) + { + I.Click(BasicPage.DropdownTab("e-print")); + + var organisations = dataTable.CreateSet(); + + foreach (var organisation in organisations) + { + _scenarioContext["OrganisationName"] = organisation.Name + _scenarioContext["GUIDPostfix"]; + + I.Click(BasicPage.AddButton); + I.FillField(BasicPage.NameField, _scenarioContext["OrganisationName"].ToString()!); + I.FillField(BasicPage.AddressField, organisation.Address!); + I.SelectOption(BasicPage.SelectorByLabel("Status"), organisation.Status!); + I.Click(BasicPage.SaveAndCloseButton); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!); + } + } + + [Then(@"I add a new site")] + public void ThenIAddANewSite(Table dataTable) + { + I.Click(BasicPage.DropdownTab("e-print")); + + var sites = dataTable.CreateSet(); + + foreach (var site in sites) + { + _scenarioContext["SiteName"] = site.Name + _scenarioContext["GUIDPostfix"]; + + I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!)); + + I.Click(BasicPage.AddButton); + I.FillField(BasicPage.NameField, _scenarioContext["SiteName"].ToString()!); + I.FillField(BasicPage.AddressField, site.Address!); + I.SelectOption(BasicPage.SelectorByLabel("Status"), site.Status!); + I.Click(BasicPage.SaveAndCloseButton); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SiteName"].ToString()!); + } + } + + [When(@"I edit existing Organisation")] + public void WhenIEditAnExistingOrganisation(Table dataTable) + { + I.Click(BasicPage.DropdownTab("e-print")); + + var organisations = dataTable.CreateSet(); + + foreach (var organisation in organisations) + { + I.Click(BasicPage.EditOrganisationButton(_scenarioContext!["OrganisationName"].ToString()!)); + + _scenarioContext!["OrganisationName"] = organisation.Name + _scenarioContext["GUID"]; + I.FillField(BasicPage.NameField, _scenarioContext["OrganisationName"].ToString()!); + I.FillField(BasicPage.AddressField, organisation.Address!); + I.SelectOption(BasicPage.SelectorByLabel("Status"), organisation.Status!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!); + _scenarioContext["OrganisationEdited"] = $"{organisation.Address!}, {_scenarioContext!["OrganisationName"]}, {organisation.Status!}"; + } + } + + [When(@"I edit existing Site")] + [Given(@"I edit existing Site")] + public void GivenIEditAnExistingUser(Table dataTable) + { + I.Click(BasicPage.DropdownTab("Home")); + I.Click(BasicPage.DropdownTab("e-print")); + I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["OrganisationName"].ToString()!)); + + var sites = dataTable.CreateSet(); + + foreach (var site in sites) + { + I.Click(BasicPage.EditOrganisationButton(_scenarioContext!["SiteName"].ToString()!)); + + _scenarioContext["SiteName"] = site.Name + _scenarioContext["GUIDPostfix"]; + + I.FillField(BasicPage.NameField, _scenarioContext["SiteName"].ToString()!); + I.FillField(BasicPage.AddressField, site.Address!); + I.SelectOption(BasicPage.SelectorByLabel("Status"), site.Status!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SiteName"].ToString()!); + _scenarioContext["SiteEdited"] = $"{site.Address!}, {_scenarioContext!["SiteName"]}, {site.Status!}"; + + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/PasswordStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/PasswordStepDefinitions.cs new file mode 100644 index 0000000..455d4e2 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/PasswordStepDefinitions.cs @@ -0,0 +1,71 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class PasswordStepDefinitions + { + private readonly IWebDriver driver; + private readonly ScenarioContext _scenarioContext; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + private readonly ConfigHelper configHelper; + private readonly LoginPage loginPage; + + public PasswordStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + configHelper = new(); + loginPage = new(driver); + } + + [When(@"I attempt to change the Password on the My Account page with: (.*)")] + [When(@"I attempt to create the Password on registration page with: (.*)")] + public void IChangeThePasswordOnTheMyAccountPage(string password) + { + BasicPage.ClickOnDropdownUserMenuItem("Account"); + I.WaitForPageToLoad(); + I.FillField(loginPage.PasswordInput, password); + } + + [When(@"The password validation should check the following criteria")] + [Then(@"The password validation should check the following criteria")] + public void ValidationPassChecking(Table dataTable) + { + var rowData = new Dictionary(); + foreach (var row in dataTable.Rows) + { + rowData.Add(row["validationText"], bool.Parse(row["passed"])); + } + + foreach (var row in rowData) + { + ValidationFieldPassed(row.Key, row.Value); + } + } + + public void ValidationFieldPassed(string validationText, bool validationPassed) + { + //IWebElement isVis =driver.FindElement(EditUsersPage.PasswordValidationSuccessString(validationText)); + switch (validationPassed) + { + case true: + Assert.IsTrue(driver.FindElement(EditUsersPage.PasswordValidationSuccessString(validationText)).Displayed, + $"Validation '{validationText}' is not visible."); + break; + + case false: + Assert.IsTrue(I.WaitTillInvisible(EditUsersPage.PasswordValidationSuccessString(validationText), 1), + $"Validation '{validationText}' is visible."); + break; + + default: + throw new Exception($"Invalid argument for validation field:'{validationPassed}'!"); + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SSOManagerManagementStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SSOManagerManagementStepDefinitions.cs new file mode 100644 index 0000000..247becc --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SSOManagerManagementStepDefinitions.cs @@ -0,0 +1,165 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class SSOManagerManagementStepDefinitions + { + private readonly IWebDriver driver; + private readonly BasicPage basicPage; + private readonly ScenarioContext _scenarioContext; + private readonly AddSsoProvider _addSsoProvider; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + + public SSOManagerManagementStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + basicPage = new BasicPage(driver); + _scenarioContext = scenarioContext; + _addSsoProvider = new AddSsoProvider(driver); + automationTestManagerHelper = new(_scenarioContext); + } + + [BeforeScenario("createssoprovider", Order = 100)] + public void CreateSSoProvider() + { + automationTestManagerHelper.CreateSsoProvider(); + } + + [AfterScenario("deletessoprovider", Order = 1)] + public void DeleteSsoCreated() + { + automationTestManagerHelper.DeleteSsoProvider(); + } + + [Given(@"I create a new SSO Provider")] + public void GivenICreateANewSSOProvider(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Sso Manager"); + var ssoProviders = dataTable.CreateSet(); + foreach (var ssoProvider in ssoProviders) + { + _scenarioContext["SSOProviderName"] = ssoProvider.Name + _scenarioContext["GUID"]; + _scenarioContext["SSOProviderCreated"] = $"{ssoProvider.AuthorisationEndpoint}, {ssoProvider.IsPublic}, {_scenarioContext["SSOProviderName"]}, {ssoProvider.TokenEndpoint}, {ssoProvider.ValidIssuer}"; + I.Click(BasicPage.AddButton); + I.FillField(AddSsoProvider.NameField, _scenarioContext["SSOProviderName"].ToString()!); + I.FillField(AddSsoProvider.ClientIDField, ssoProvider.ClientID!); + I.FillField(AddSsoProvider.ClientSecretField, ssoProvider.ClientSecret!); + I.FillField(AddSsoProvider.ValidIssuerField, ssoProvider.ValidIssuer!); + I.FillField(AddSsoProvider.AuthorisationEndpointField, ssoProvider.AuthorisationEndpoint!); + I.FillField(AddSsoProvider.TokenEndpointField, ssoProvider.TokenEndpoint!); + + if (!ssoProvider.IsPublic!.Equals("true")) + { + if (I.WaitForElementToBeChecked(AddSsoProvider.IsPublicCheckBox)) + { + I.Click(AddSsoProvider.IsPublicCheckBox); + } + } + + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + } + I.WaitForVisible(BasicPage.ToastWithMessage("New Sso Provider added")); + I.Click(BasicPage.DropdownTab("Home")); + } + + [Then(@"^new SSO Provider is (present|not present) on the list$")] + public void ThenNewSSOProviderIsPresentOnTheList(string presence) + { + BasicPage.ClickOnDropdownMenuItem("Sso Manager"); + switch (presence) + { + case "present": + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!, AddSsoProvider.DisplayNameSearchField); + break; + case "not present": + BasicPage.SearchDeletedObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!); + break; + } + } + + [When(@"I edit existing SSO Provider")] + public void WhenIEditExistingSSOProvider(Table dataTable) + { + var editSsoProviders = dataTable.CreateSet(); + BasicPage.ClickOnDropdownMenuItem("Sso Manager"); + I.WaitForElementVisibleAndClickable(BasicPage.SearchInput); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SSOProviderName"].ToString()!); + I.Click(BasicPage.EditObjectButton(_scenarioContext["SSOProviderName"].ToString()!)); + + foreach (var editSsoProvider in editSsoProviders) + { + _scenarioContext["SSOProviderName"] = editSsoProvider.Name + _scenarioContext["GUIDPostfix"]; + _scenarioContext["ClientID"] = editSsoProvider.ClientID; + _scenarioContext["ClientSecret"] = editSsoProvider.ClientSecret; + _scenarioContext["ValidIssuer"] = editSsoProvider.ValidIssuer; + _scenarioContext["AuthorisationEndpoint"] = editSsoProvider.AuthorisationEndpoint; + _scenarioContext["TokenEndpoint"] = editSsoProvider.TokenEndpoint; + _scenarioContext["IsPublic"] = editSsoProvider.IsPublic; + string clientIdHidden = "", clientSecretHidden = ""; + _scenarioContext["SSOProviderEdited"] = $"{editSsoProvider.AuthorisationEndpoint}, {clientIdHidden}, {clientSecretHidden}, {editSsoProvider.IsPublic}, {_scenarioContext["SSOProviderName"]}, {editSsoProvider.TokenEndpoint}, {editSsoProvider.ValidIssuer}"; + + I.FillField(AddSsoProvider.NameField, _scenarioContext["SSOProviderName"].ToString()!); + I.FillField(AddSsoProvider.ClientIDField, editSsoProvider.ClientID!); + I.FillField(AddSsoProvider.ClientSecretField, editSsoProvider.ClientSecret!); + I.FillField(AddSsoProvider.ValidIssuerField, editSsoProvider.ValidIssuer!); + I.FillField(AddSsoProvider.AuthorisationEndpointField, editSsoProvider.AuthorisationEndpoint!); + I.FillField(AddSsoProvider.TokenEndpointField, editSsoProvider.TokenEndpoint!); + if (!editSsoProvider.IsPublic!.Equals("true")) + { + if (I.WaitForElementToBeChecked(AddSsoProvider.IsPublicCheckBox)) + { + I.Click(AddSsoProvider.IsPublicCheckBox); + } + } + + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + } + + I.WaitForVisible(BasicPage.ToastWithMessage("Sso Provider edited")); + I.Click(BasicPage.DropdownTab("Home")); + } + + [Then(@"I check edited data on SSO Provider page")] + public void ThenICheckEditedDataOnSSOProviderPage() + { + BasicPage.ClickOnDropdownMenuItem("Sso Manager"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SSOProviderName"].ToString()!, AddSsoProvider.DisplayNameSearchField); + I.Click(BasicPage.EditObjectButton(_scenarioContext["SSOProviderName"].ToString()!)); + I.WaitForElementWithAttributeValue(AddSsoProvider.NameField, "value", _scenarioContext["SSOProviderName"].ToString()!); + I.WaitForElementWithAttributeValue(AddSsoProvider.ClientIDField, "value", _scenarioContext["ClientID"].ToString()!); + I.WaitForElementWithAttributeValue(AddSsoProvider.ClientSecretField, "value", _scenarioContext["ClientSecret"].ToString()!); + I.WaitForElementWithAttributeValue(AddSsoProvider.ValidIssuerField, "value", _scenarioContext["ValidIssuer"].ToString()!); + I.WaitForElementWithAttributeValue(AddSsoProvider.AuthorisationEndpointField, "value", _scenarioContext["AuthorisationEndpoint"].ToString()!); + I.WaitForElementWithAttributeValue(AddSsoProvider.TokenEndpointField, "value", _scenarioContext["TokenEndpoint"].ToString()!); + if (_scenarioContext["IsPublic"].ToString()!.Equals("true")) + { + Assert.IsTrue(I.WaitForElementToBeChecked(AddSsoProvider.IsPublicCheckBox, 1)); + } + else + { + Assert.IsFalse(I.WaitForElementToBeChecked(AddSsoProvider.IsPublicCheckBox, 1)); + } + } + + [When(@"I delete existing SSO Provider")] + public void WhenIDeleteExistingSSOProvider() + { + BasicPage.ClickOnDropdownMenuItem("Sso Manager"); + I.WaitForElementVisibleAndClickable(BasicPage.SearchInput); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SSOProviderName"].ToString()!); + I.Click(BasicPage.DeleteObjectButton(_scenarioContext["SSOProviderName"].ToString()!)); + I.WaitTillInvisible(BasicPage.DeleteObjectButton(_scenarioContext["SSOProviderName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SequenceStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SequenceStepDefinitions.cs new file mode 100644 index 0000000..63933c4 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SequenceStepDefinitions.cs @@ -0,0 +1,110 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class SequenceStepDefinitions + { + private readonly IWebDriver driver; + private readonly BasicPage basicPage; + private readonly AddSequencePage addSequencePage; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + private readonly ScenarioContext _scenarioContext; + + public SequenceStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + basicPage = new(driver); + addSequencePage = new(driver); + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + } + + [BeforeScenario("createsequence", Order = 14)] + public async Task GivenCreateSequenceViaApi() + { + await automationTestManagerHelper.CreateSequence(); + } + + [Given(@"I create a new Sequence via API")] + public async Task GivenCreateSequenceViaApi(Table dataTable) + { + var sequences = dataTable.CreateSet(); + foreach (var sequence in sequences) + { + await automationTestManagerHelper.CreateSequence(sequence.Name); + } + } + + [Given(@"I create a new Sequence")] + [When(@"I create a new Sequence")] + public void GivenICreateASequenceWithRolloverTypeDay(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Sequence"); + + var sequences = dataTable.CreateSet(); + + foreach (var sequence in sequences) + { + + _scenarioContext["SequenceName"] = sequence.Name + _scenarioContext["GUIDPostfix"]; + + I.Click(BasicPage.AddButton); + I.FillField(BasicPage.NameField, _scenarioContext["SequenceName"].ToString()!); + I.FillField(AddSequencePage.SeedField, sequence.Seed!); + I.FillField(AddSequencePage.IncrementField, sequence.Increment!); + I.FillField(AddSequencePage.PatternField, sequence.Pattern!); + I.SelectOption(AddSequencePage.RolloverTypeSelector, sequence.RolloverType!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SequenceName"].ToString()!); + _scenarioContext["SequenceCreated"] = $"{"false"}, {sequence.Increment}, {_scenarioContext["SequenceName"]}, {sequence.Pattern!}, " + + $"{sequence.RolloverType}, {sequence.Seed!}"; + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + + } + } + + [Given(@"I update existing Sequence")] + [When(@"I update existing Sequence")] + public void WhenIUpdateASequence(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Sequence"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SequenceName"].ToString()!); + var sequences = dataTable.CreateSet(); + + foreach (var sequence in sequences) + { + + I.Click(BasicPage.EditObjectButton(_scenarioContext["SequenceName"].ToString()!)); + _scenarioContext["SequenceName"] = sequence.Name + _scenarioContext["GUIDPostfix"]; + I.FillField(BasicPage.NameField, _scenarioContext["SequenceName"].ToString()!); + I.FillField(AddSequencePage.SeedField, sequence.Seed!); + I.FillField(AddSequencePage.IncrementField, sequence.Increment!); + I.FillField(AddSequencePage.PatternField, sequence.Pattern!); + I.SelectOption(AddSequencePage.RolloverTypeSelector, sequence.RolloverType!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + _scenarioContext["SequenceEdited"] = $"{sequence.Increment}, {_scenarioContext["SequenceName"]}, {sequence.Pattern!}, " + + $"{sequence.RolloverType}, {sequence.Seed!}"; + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + + } + } + + [When(@"I delete a sequence")] + public void WhenIDeleteASequence() + { + BasicPage.ClickOnDropdownMenuItem("Sequence"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SequenceName"].ToString()!); + I.Click(BasicPage.DeleteObjectButton(_scenarioContext["SequenceName"].ToString()!)); + I.WaitTillInvisible(BasicPage.DeleteObjectButton(_scenarioContext["SequenceName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + BasicPage.SearchDeletedObjectNameInTableViaSearchInputField(_scenarioContext["SequenceName"].ToString()!); + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SpecificationManagerStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SpecificationManagerStepDefinitions.cs new file mode 100644 index 0000000..2e7f7ef --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/SpecificationManagerStepDefinitions.cs @@ -0,0 +1,364 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; +using System.Text.RegularExpressions; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class SpecificationManagerStepDefinitions + { + private readonly IWebDriver driver; + private readonly ScenarioContext _scenarioContext; + private readonly ConfigHelper configHelper; + + + public SpecificationManagerStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + _scenarioContext = scenarioContext; + configHelper = new(); + } + + [When(@"I added a Form Template into the Print Specifications")] + public void ThenIAddedAFormIntoPrintSpecifications(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Glossaries"); + var specifications = dataTable.CreateSet(); + foreach (var specification in specifications) + { + _scenarioContext["PrintSpecificationName"] = specification.Name + _scenarioContext["GUIDPostfix"]; + I.Click(By.LinkText("Print Specifications")); + I.Click(BasicPage.AddButton); + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.FillField(BasicPage.NameField, _scenarioContext["PrintSpecificationName"].ToString()!); + I.SelectOption(AddGlossariesPage.PrintSpecificationFormTemplateFieldSelector, _scenarioContext["FormName"]!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitForVisible(BasicPage.ToastWithMessage("New Glossary Item added")); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + } + } + + [Then(@"^I (create|edit) a Specification$")] + [When(@"^I (create|edit) a Specification$")] + public void ThenICreateASpecification(string action, Table dataTable) + { + I.Click(BasicPage.DropdownTab("e-print")); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!); + I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!)); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SiteName"].ToString()!); + I.Click(By.LinkText(_scenarioContext["SiteName"].ToString()!)); + + var specifications = dataTable.CreateSet(); + + if (action == "create") + { + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.Click(BasicPage.AddButton); + I.WaitTillInvisible(BasicPage.AddButton); + I.WaitForPageToLoad(); + + foreach (var specification in specifications) + { + FillSpecification(specification); + } + } + else if (action == "edit") + { + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SpecificationName"].ToString()!); + I.Click(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.WaitForPageToLoad(); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + + foreach (var specification in specifications) + { + FillSpecification(specification); + } + } + + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SpecificationName"].ToString()!); + + _scenarioContext["Specification"] = $"{"false"}, {_scenarioContext!["SpecificationName"]}, {_scenarioContext!["SiteName"]}"; + _scenarioContext["SpecificationEdited"] = $"{_scenarioContext!["SpecificationName"]}"; + } + + [Then(@"^I can not (create|edit) a Specification with required fields and empty value$")] + [When(@"^I can not (create|edit) a Specification with required fields and empty value$")] + public void ThenICanNotCreateASpecification(string action, Table dataTable) + { + I.Click(BasicPage.DropdownTab("e-print")); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!); + I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!)); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SiteName"].ToString()!); + I.Click(By.LinkText(_scenarioContext["SiteName"].ToString()!)); + + var specifications = dataTable.CreateSet(); + + if (action == "create") + { + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.Click(BasicPage.AddButton); + I.WaitTillInvisible(BasicPage.AddButton); + I.WaitForPageToLoad(); + + foreach (var specification in specifications) + { + FillSpecification(specification); + } + } + else if (action == "edit") + { + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SpecificationName"].ToString()!); + I.Click(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.LoadingMessage); + I.WaitForPageToLoad(); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + + foreach (var specification in specifications) + { + FillSpecification(specification); + } + } + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + + _scenarioContext["Specification"] = $"{"false"}, {_scenarioContext!["SpecificationName"]}, {_scenarioContext!["SiteName"]}"; + _scenarioContext["SpecificationEdited"] = $"{_scenarioContext!["SpecificationName"]}"; + } + + [Then(@"^new Specification is (present|not present) on the list$")] + [When(@"^new Specification is (present|not present) on the list$")] + public void ThenNewSpecificationIsPresentOnTheList(string presence) + { + I.Click(BasicPage.DropdownTab("Home")); + I.Click(BasicPage.DropdownTab("e-print")); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext!["OrganisationName"].ToString()!); + I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["OrganisationName"].ToString()!)); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext!["SiteName"].ToString()!); + I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["SiteName"].ToString()!)); + + switch (presence) + { + case "present": + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!, BasicPage.SearchInput); + break; + case "not present": + BasicPage.SearchDeletedObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!); + break; + } + } + + [When(@"I delete existing Specification")] + [Then(@"I delete existing Specification")] + public void WhenIDeleteExistingSSOProvider() + { + I.Click(BasicPage.DropdownTab("Home")); + I.Click(BasicPage.DropdownTab("e-print")); + I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["OrganisationName"].ToString()!)); + I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["SiteName"].ToString()!)); + I.Click(BasicPage.DeleteObjectButton(_scenarioContext["SpecificationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.DeleteObjectButton(_scenarioContext["SpecificationName"].ToString()!)); + I.Click(BasicPage.ConfirmDeletionButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + + [Then(@"I check data on Specification")] + public void ThenICheckEditedDataOnSSOProviderPage(Table dataTable) + { + var specifications = dataTable.CreateSet(); + RetryHelper.Retry(() => + { + I.Click(BasicPage.DropdownTab("e-print")); + + I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!)); + I.Click(By.LinkText(_scenarioContext["SiteName"].ToString()!)); + I.Click(BasicPage.EditObjectButton(_scenarioContext["SpecificationName"].ToString()!)); + I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext["SpecificationName"].ToString()!)); + I.WaitForPageToLoad(); + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + + I.WaitForElementWithAttributeValue(BasicPage.NameField, "value", _scenarioContext["SpecificationName"].ToString()!); + foreach (var specification in specifications) + { + switch (specification.SpecificationItems) + { + case "Glossary": + var actualGlossary = I.ReturnSelectedOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), 1); + if (specification.ItemValue!.Equals("dataFromScenarioContext")) + { + var glossaryFromScenarioContext = _scenarioContext["GlossaryItemName"].ToString()!; + Assert.AreEqual(glossaryFromScenarioContext, actualGlossary, $"Expected Glossary is: {glossaryFromScenarioContext}, but found: {actualGlossary}"); + } + else + { + string expectedGlossary = specification.ItemValue ?? ""; + Assert.AreEqual(expectedGlossary, actualGlossary, $"Expected Glossary is: {expectedGlossary}, but found: {actualGlossary}"); + } + break; + case "Domain": + var actualDomain = I.ReturnSelectedOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), 1); + + if (specification.ItemValue!.Equals("dataFromScenarioContext")) + { + var domainFromScenarioContext = _scenarioContext!["DomainName"].ToString()!; + Assert.AreEqual(domainFromScenarioContext, actualDomain, $"Expected Domain is: {domainFromScenarioContext}, but found: {actualDomain}"); + } + else + { + string expectedDomain = specification.ItemValue ?? ""; + Assert.AreEqual(expectedDomain, actualDomain, $"Expected Domain is: {expectedDomain}, but found: {actualDomain}"); + } + break; + case "Text": + + if (specification.ItemValue!.Equals("dataFromScenarioContext")) + { + var actualText = I.GetText(AddSpecificationsPage.PrintSpecificationTextAreaItem(specification.SpecificationItems)!, 1); + var textFromScenarioContext = _scenarioContext!["Text"].ToString()!; + Assert.AreEqual(textFromScenarioContext, actualText, $"Expected Text is: {textFromScenarioContext}, but found: {actualText}"); + } + else + { + var actualText = I.GetText(AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems)!, 1); + string expectedText = specification.ItemValue ?? ""; + Assert.AreEqual(expectedText, actualText, $"Expected Text is: {expectedText}, but found: {actualText}"); + } + break; + case "Sequence": + if (specification.ItemValue!.Equals("dataFromScenarioContext")) + { + var regexMatch = @"ID:\d{6}\s+Date:\d{2}"; + var input = I.GetValueAttribute(AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems)!, 1); + Assert.IsTrue(Regex.IsMatch(input, regexMatch), $"Sequence {input} doesn't match the regex {regexMatch}"); + } + break; + case "Form Template": + var actualFormTemplate = I.ReturnSelectedOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), 1); + + if (specification.ItemValue!.Equals("dataFromScenarioContext")) + { + var expectedFormTemplate = _scenarioContext["ChildFormName"].ToString()!; + Assert.AreEqual(expectedFormTemplate, actualFormTemplate, $"Expected Form Template is: {expectedFormTemplate}, but found: {actualFormTemplate}"); + } + else + { + var expectedFormTemplate = _scenarioContext["FormName"].ToString()!; + Assert.AreEqual(expectedFormTemplate, actualFormTemplate, $"Expected Form Template is: {expectedFormTemplate}, but found: {actualFormTemplate}"); + } + break; + case "Number": + var actualNumber = AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems); + + if (specification.ItemValue!.Equals("dataFromScenarioContext")) + { + var numberFromScenarioContext = _scenarioContext!["Number"].ToString()!; + I.WaitForElementWithAttributeValue(actualNumber, "value", numberFromScenarioContext, 1); + } + else + { + string expectedNumber = specification.ItemValue ?? ""; + I.WaitForElementWithAttributeValue(actualNumber, "value", expectedNumber, 1); + } + break; + default: + break; + } + } + }); + } + + private void FillSpecification(SpecificationsData specification) + { + I.DebounceDelay(configHelper.DebounceDelayMilliseconds); + if (!string.IsNullOrEmpty(specification.Name)) _scenarioContext["SpecificationName"] = specification.Name + _scenarioContext["GUID"]; + if (!string.IsNullOrEmpty(specification.Name)) I.FillField(BasicPage.NameField, _scenarioContext["SpecificationName"].ToString()!); + if (!string.IsNullOrEmpty(specification.PrintSpecification)) I.SelectOption(AddSpecificationsPage.PrintSpecificationSelector, _scenarioContext["PrintSpecificationName"]!); + switch (specification.SpecificationItems) + { + case "Glossary": + if (specification.ItemValue!.Equals("defaultGlossary") && !specification.MultiselectField == true) + { + I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), _scenarioContext["GlossaryItemName"]!); + _scenarioContext["FormFieldInstance"] = $"{_scenarioContext["GlossaryItemName"]}"; + } + else if (!string.IsNullOrEmpty(specification.ItemValue) && !specification.MultiselectField == true) + { + var glossaries = _scenarioContext["GlossaryList"] as List; + if (glossaries != null) + { + var differentGlossary = glossaries.FirstOrDefault(x => x.Contains("TestBlackGlossaryItemDifferent", StringComparison.OrdinalIgnoreCase)); + I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), differentGlossary!); + _scenarioContext["FormFieldInstance"] = $"{differentGlossary}"; + } + } + else if (specification.ItemValue!.Equals("defaultGlossary") && specification.MultiselectField == true) + { + var glossaries = _scenarioContext["GlossaryList"] as List; + for (int i = 0; i < specification.NumberOfItems && i < glossaries!.Count; i++) + { + string glossary = glossaries[i]; + I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectField); + I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectItem(glossary)); + } + } + break; + case "Domain": + if (!string.IsNullOrEmpty(specification.ItemValue) && !specification.MultiselectField == true) + { + I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), _scenarioContext!["DomainName"]!); + } + else if (specification.ItemValue!.Equals("default") && specification.MultiselectField == true) + { + if (_scenarioContext["DomainList"] is List domains) + { + for (int i = 0; i < specification.NumberOfItems && i < domains!.Count; i++) + { + string domain = domains[i]; + I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectField); + I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectItem(domain)); + } + } + } + break; + case "Text": + if (!string.IsNullOrEmpty(specification.ItemValue)) + I.FillField(AddSpecificationsPage.PrintSpecificationTextAreaItem(specification.SpecificationItems), specification.ItemValue!); + _scenarioContext["Text"] = specification.ItemValue!; + break; + case "Sequence": + break; + case "Form Template": + if (!string.IsNullOrEmpty(specification.ItemValue)) + I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), _scenarioContext["ChildFormName"]!); + break; + case "Number": + if (!string.IsNullOrEmpty(specification.ItemValue)) + I.FillField(AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems), specification.ItemValue!); + _scenarioContext["Number"] = specification.ItemValue!; + break; + default: + break; + } + } + + [Then(@"Error toast message is present")] + public static void ThenErrorToastMessageIsPresent(Table dataTable) + { + var commonData = dataTable.CreateSet(); + foreach (var data in commonData) + { + I.WaitForVisible(BasicPage.ToastWithMessage(data.Message!)); + } + } + } +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/UserAuthenticationStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/UserAuthenticationStepDefinitions.cs new file mode 100644 index 0000000..488e9aa --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/UserAuthenticationStepDefinitions.cs @@ -0,0 +1,205 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; +using OpenQA.Selenium.Support.UI; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class UserAuthenticationStepDefinitions + { + private readonly IWebDriver driver; + private readonly LoginPage loginPage; + private readonly EditUsersPage editUsersPage; + private readonly ScenarioContext _scenarioContext; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + private readonly TestEnvironment testEnvironment; + private readonly ConfigHelper configHelper; + private readonly APIHelper apiHelper; + + public UserAuthenticationStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + loginPage = new LoginPage(driver); + editUsersPage = new EditUsersPage(driver); + _scenarioContext = scenarioContext; + automationTestManagerHelper = new(_scenarioContext); + testEnvironment = new TestEnvironment(); + configHelper = new ConfigHelper(); + apiHelper = new(_scenarioContext); + + } + + [BeforeScenario("auth", Order = 500)] + [When(@"I login as Admin")] + public void BeforeScenarioWithAuth() + { + AuthenticationHelper.LoginWithCredentials(testEnvironment.Username, testEnvironment.Password, configHelper.BaseUrl); + } + + [BeforeScenario("createuser", Order = 80)] + [Given(@"I create a new user via API")] + public async Task CreateUserAsync() + { + await automationTestManagerHelper.CreateUser(); + var users = await apiHelper.GetUsers(configHelper.APIUrl); + var data = users["data"]!.ElementAt(0); + int userId = (int)data["id"]!; + string userEmail = (string)data["email"]!; + Guid userGuid = Guid.Parse((string)data["guid"]!); + Assert.AreEqual(userEmail, _scenarioContext["UserEmail"].ToString()!); + _scenarioContext["UserId"] = userId; + _scenarioContext["UserGUID"] = userGuid; + } + + [AfterScenario("deleteuser", Order = 2)] + [Given(@"I delete existing user")] + [When(@"I delete existing user")] + [Then(@"I delete existing user")] + public void DeleteUser() + { + automationTestManagerHelper.DeleteUser(); + } + + [AfterScenario("deleteuserapi", Order = 22)] + [Given(@"I delete existing user via API")] + [When(@"I delete existing user via API")] + [Then(@"I delete existing user via API")] + public async Task DeleteUserViaAPIAsync() + { + await automationTestManagerHelper.DeleteUserAPI(); + } + + [Given(@"I enter valid credentials via login page")] + public void WhenIEnterValidCredentials() + { + AuthenticationHelper.LoginWithCredentials(testEnvironment.Username, testEnvironment.Password, testEnvironment.BaseUrl); + } + + [AfterScenario("logout", Order = 200)] + [Given(@"I logout")] + [When(@"I logout")] + [Then(@"I logout")] + public void Logout() + { + AuthenticationHelper.Logout(configHelper.BaseUrl); + } + + [Then(@"I successfully login with new credentials and I do not see the login page anymore")] + [Given(@"I successfully login with new credentials and I do not see the login page anymore")] + public void ThenISuccessfullyLoginWithNewCredentials() + { + AuthenticationHelper.LoginWithCredentials(_scenarioContext["UserEmail"].ToString()!, _scenarioContext["Password"].ToString()!, configHelper.BaseUrl); + WebDriverWait wait = new(driver, TimeSpan.FromSeconds(configHelper.ClickWaitSeconds)); + wait.Until(btn => !btn.Url.Contains("login")); + } + + [Then(@"I successfully login with new credentials and 2FA")] + [Given(@"I successfully login with new credentials and 2FA")] + public void ThenISuccessfullyLoginWithNewCredentialsAnd2FA() + { + AuthenticationHelper.LoginWithCredentials2FA(_scenarioContext["UserEmail"].ToString()!, _scenarioContext["Password"].ToString()!, configHelper.BaseUrl, _scenarioContext); + WebDriverWait wait = new(driver, TimeSpan.FromSeconds(configHelper.ClickWaitSeconds)); + wait.Until(btn => !btn.Url.Contains("login")); + } + + [Then(@"I enter a new password and confirm it")] + [Then(@"I enter a new password and confirm it and add 2FA")] + public void ThenIEnterANewPasswordAndConfirmIt(Table dataTable) + { + var users = dataTable.CreateSet(); + I.WaitForPageToLoad(); + + foreach (var user in users) + { + _scenarioContext["Password"] = user.Password + _scenarioContext["GUIDPostfix"]; + + EnterNewPasswordAndConfirmIt(); + + if (string.Equals(user.MFA ?? "", "true", StringComparison.OrdinalIgnoreCase)) + { + EnterNew2FA(); + } + I.Click(loginPage.ActivateButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + WebDriverWait wait = new(driver, TimeSpan.FromSeconds(configHelper.ClickWaitSeconds)); + wait.Until(btn => btn.Url.Contains("login")); + I.WaitForVisible(loginPage.EmailInput); + } + } + + [Then(@"I assign Admin role to the user")] + public async Task AssignAdminRoleToUser() + { + + var userId = int.Parse(_scenarioContext["UserId"].ToString()!); + Guid userGuid = new(_scenarioContext["UserGUID"].ToString()!); + await automationTestManagerHelper.AssignAdminRole(userId, userGuid); + } + + [Then(@"I am resetting the password for the newly created user")] + public void ResettingThePasswordForTheNewlyCreatedUser() + { + I.NavigateToURL($"{configHelper.BaseUrl}/login"); + I.FillField(loginPage.EmailInput, _scenarioContext["UserEmail"].ToString()!); + I.Click(loginPage.NextButton); + I.Click(loginPage.ForgottenPasswordButton); + I.WaitForVisible(loginPage.ForgottenPasswordMessageAlert); + } + + [Then(@"I enter a new password and save it")] + public void ThenIEnterNewPasswordAndSaveIt(Table dataTable) + { + var users = dataTable.CreateSet(); + + foreach (var user in users) + { + _scenarioContext["Password"] = user.Password + _scenarioContext["GUIDPostfix"]; + + EnterNewPasswordAndConfirmIt(); + I.Click(loginPage.SaveButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + } + + [When("I try to delete existing user")] + public void WhenITryToDeleteExistingUser() + { + var entityName = _scenarioContext["UserName"].ToString()!; + AutomationTestManagerHelper.NavigateToMenu("Users"); + BasicPage.SearchObjectNameInTableViaSearchInputField(entityName, AddUsersPage.DisplayNameSearchField); + } + + [Then(@"^I (can|can't) delete myself$")] + public void ThenICantDeleteMyself(string presence) + { + var entityName = _scenarioContext["UserName"].ToString()!; + switch (presence) + { + case "can": + I.WaitForVisible(BasicPage.DeleteObjectButton(entityName)); + break; + case "can't": + I.WaitTillInvisible(BasicPage.DeleteObjectButton(entityName), 2); + break; + } + } + + public void EnterNewPasswordAndConfirmIt() + { + I.FillField(loginPage.PasswordInput, _scenarioContext["Password"].ToString()!); + I.FillField(loginPage.ConfirmPasswordInput, _scenarioContext["Password"].ToString()!); + } + + private void EnterNew2FA() + { + I.Click(editUsersPage.MFACheckbox); + var secretKey = I.GetText(editUsersPage.MFAKey); + _scenarioContext["SecretKey"] = secretKey; + var code = AuthenticationHelper.GenerateOTP(_scenarioContext["SecretKey"].ToString()!, _scenarioContext); + I.FillField(editUsersPage.MFACodeField, code); + } + } +} \ No newline at end of file diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/UserCreationAndEditingStepDefinitions.cs b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/UserCreationAndEditingStepDefinitions.cs new file mode 100644 index 0000000..00fa9af --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/StepDefinitions/UserCreationAndEditingStepDefinitions.cs @@ -0,0 +1,151 @@ +using ESuite.UI.E2E.Helpers; +using ESuite.UI.E2E.Helpers.Mail; +using ESuite.UI.E2E.Models; +using ESuite.UI.E2E.Pages; +using OpenQA.Selenium; + +namespace ESuite.UI.E2E.StepDefinitions +{ + [Binding] + public class UserCreationAndEditingStepDefinitions + { + private readonly IWebDriver driver; + private readonly EditUsersPage editUsersPage; + private readonly UserAuthenticationStepDefinitions userAuthenticationStepDefinitions; + private readonly Mailer mailer; + private readonly ScenarioContext _scenarioContext; + private readonly APIHelper apiHelper; + private readonly ConfigHelper configHelper; + private readonly AutomationTestManagerHelper automationTestManagerHelper; + + + public UserCreationAndEditingStepDefinitions(ScenarioContext scenarioContext) + { + driver = WebDriverHelper.GetWebDriver(); + editUsersPage = new EditUsersPage(driver); + mailer = new Mailer(); + _scenarioContext = scenarioContext; + apiHelper = new APIHelper(_scenarioContext); + configHelper = new ConfigHelper(); + userAuthenticationStepDefinitions = new(_scenarioContext); + automationTestManagerHelper = new(_scenarioContext); + + } + + [Given(@"I create a new user")] + public void GivenICreateANewUser(Table dataTable) + { + BasicPage.ClickOnDropdownMenuItem("Users"); + + var users = dataTable.CreateSet(); + + foreach (var user in users) + { + _scenarioContext["UserName"] = $"{user.FirstName} {user.MiddleNames} {user.LastName}"; + _scenarioContext["UserEmail"] = Mailer.CustomizeUserEmail(user.Mail!, _scenarioContext["GUID"].ToString()!); + + I.Click(BasicPage.AddButton); + I.FillField(AddUsersPage.MailField, _scenarioContext["UserEmail"].ToString()!); + I.FillField(AddUsersPage.FirstNameField, user.FirstName!); + I.FillField(AddUsersPage.MiddleNamesField, user.MiddleNames!); + I.FillField(AddUsersPage.LastNameField, user.LastName!); + I.SelectOption(BasicPage.SelectorByLabel("Domain"), user.Domain!); + I.Click(BasicPage.SaveAndCloseButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + I.WaitTillInvisible(BasicPage.SaveAndCloseButton); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!, AddUsersPage.EmailSearchField); + } + } + + [Given(@"I create a new user through an API call")] + public void GivenICreateANewUserThroughAPICall(Table dataTable) + { + Task.Run(async () => + { + var users = dataTable.CreateSet(); + int userCount = 1; + + + foreach (var user in users) + { + string email = Mailer.CustomizeUserEmail(user.Mail!, _scenarioContext["GUID"].ToString()!); + + if (userCount > 1) + { + _scenarioContext[$"UserName{userCount}"] = $"{user.FirstName} {user.MiddleNames} {user.LastName}"; + _scenarioContext[$"UserEmail{userCount}"] = email; + } + else + { + _scenarioContext["UserName"] = $"{user.FirstName} {user.MiddleNames} {user.LastName}"; + _scenarioContext["UserEmail"] = email; + } + + var domains = await apiHelper.GetDomains(configHelper.APIUrl); + var data = domains["data"]!.ElementAt(0); + int domainId = (int)data["id"]!; + + await apiHelper.CreateNewUser( + configHelper.APIUrl, + user.FirstName!, + user.MiddleNames!, + user.LastName!, + email, + domainId + ); + + userCount++; + } + }); + } + + [When(@"I edit an existing user")] + public void GivenIEditAnExistingUser(Table dataTable) + { + BasicPage.ClickOnDropdownUserMenuItem("Account"); + + var editUsers = dataTable.CreateSet(); + + foreach (var editUser in editUsers) + { + _scenarioContext["FirstName"] = editUser.EditedFirstName + _scenarioContext["GUID"]; + _scenarioContext["MiddleNames"] = editUser.EditedMiddleNames; + _scenarioContext["LastName"] = editUser.EditedLastName; + _scenarioContext["UserName"] = $"{_scenarioContext["FirstName"]} {editUser.EditedMiddleNames} {editUser.EditedLastName}"; + _scenarioContext["UserNameEdited"] = $"{_scenarioContext["FirstName"]}, {editUser.EditedLastName}, {editUser.EditedLastName}, {""}"; + + I.FillField(editUsersPage.FirstNameField, _scenarioContext["FirstName"].ToString()!); + I.FillField(editUsersPage.MiddleNamesField, editUser.EditedMiddleNames!); + I.FillField(editUsersPage.LastNameField, editUser.EditedLastName!); + if (!string.IsNullOrEmpty(editUser.Password)) + { + _scenarioContext["Password"] = editUser.Password + _scenarioContext["GUIDPostfix"]; + + userAuthenticationStepDefinitions.EnterNewPasswordAndConfirmIt(); + } + if (editUsersPage.MFACheckbox != null && string.Equals(editUser.MFA ?? "", "true", StringComparison.CurrentCultureIgnoreCase) && !(I.WaitForElementToBeChecked(editUsersPage.MFACheckbox, 1))) + { + I.Click(editUsersPage.MFACheckbox); + } + else if (editUsersPage.MFACheckbox != null && string.Equals(editUser.MFA ?? "", "false", StringComparison.CurrentCultureIgnoreCase) && (I.WaitForElementToBeChecked(editUsersPage.MFACheckbox, 1))) + { + I.Click(editUsersPage.MFACheckbox); + } + I.Click(BasicPage.SaveButton); + AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext); + } + } + + [Then(@"I check edited data on edit user page")] + public void ThenICheckEditedDataOnEditUserPage() + { + BasicPage.ClickOnDropdownMenuItem("Users"); + BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["UserEmail"].ToString()!, AddUsersPage.EmailSearchField); + I.Click(BasicPage.EditObjectButton(_scenarioContext["UserEmail"].ToString()!)); + I.WaitForElementWithAttributeValue(AddUsersPage.FirstNameField, "value", _scenarioContext["FirstName"].ToString()!); + I.WaitForElementWithAttributeValue(AddUsersPage.MiddleNamesField, "value", _scenarioContext["MiddleNames"].ToString()!); + I.WaitForElementWithAttributeValue(AddUsersPage.LastNameField, "value", _scenarioContext["LastName"].ToString()!); + } + } +} + diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/config.Auto.json b/e-suite.Automation.UITests/ESuite.UI.E2E/config.Auto.json new file mode 100644 index 0000000..b9ee40c --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/config.Auto.json @@ -0,0 +1,9 @@ +{ + "BaseUrl": "https://e-suite-auto-test-proxy.azurewebsites.net", + "APIUrl": "https://e-suite-auto-api.azurewebsites.net", + "ClickWaitSeconds": 60, + "HeadlessMode": true, + "DebounceDelayMilliseconds": 2500, + "TestMailAppAPIKey": "", + "TestMailAppNamespace": "" +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/config.Debug.json b/e-suite.Automation.UITests/ESuite.UI.E2E/config.Debug.json new file mode 100644 index 0000000..f368857 --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/config.Debug.json @@ -0,0 +1,9 @@ +{ + "BaseUrl": "http://localhost:3001", + "APIUrl": "http://localhost:3001", + "ClickWaitSeconds": 60, + "DebounceDelayMilliseconds": 2500, + "HeadlessMode": false, + "TestMailAppAPIKey": "", + "TestMailAppNamespace": "" +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/config.Release.json b/e-suite.Automation.UITests/ESuite.UI.E2E/config.Release.json new file mode 100644 index 0000000..19b932e --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/config.Release.json @@ -0,0 +1,9 @@ +{ + "BaseUrl": "#{BASE_URL}#", + "APIUrl": "#{API_URL}#", + "ClickWaitSeconds": 60, + "DebounceDelayMilliseconds": 2500, + "HeadlessMode": true, + "TestMailAppAPIKey": "#{TESTMAIL_API_KEY}#", + "TestMailAppNamespace": "#{TESTMAIL_NAMESPACE}#" +} diff --git a/e-suite.Automation.UITests/ESuite.UI.E2E/reqnroll.json b/e-suite.Automation.UITests/ESuite.UI.E2E/reqnroll.json new file mode 100644 index 0000000..3e5572e --- /dev/null +++ b/e-suite.Automation.UITests/ESuite.UI.E2E/reqnroll.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://schemas.reqnroll.net/reqnroll-config-latest.json", + "generator": { + "allowRowTests": false + } +} diff --git a/e-suite.Automation.UITests/README.md b/e-suite.Automation.UITests/README.md new file mode 100644 index 0000000..dc11e75 --- /dev/null +++ b/e-suite.Automation.UITests/README.md @@ -0,0 +1,108 @@ +# Automated UI End to End(E2E) tests using ReqnRoll BDD, MSTest, and Chrome + +## Prerequisites + +- Visual Studio with ReqnRoll extension installed +- Chrome browser installed +- .NET Core SDK (please take a look of required version) + +## Project Setup + +1. Create a new SpecFlow project in Visual Studio. + +2. Install the required NuGet packages: + - Reqnroll + - Reqnroll.MSTest + - Selenium.WebDriver + - Selenium.WebDriver.ChromeDriver + + +## Writing the Test. Example + +1. Create a new feature file named "Login.feature" in the "Features" folder of your SpecFlow project. + +2. Add the following scenario to the "Login.feature" file: + +```gherkin +Feature: User Authentication + In order to access my account + As a user + I want to be able to authenticate in the system + +Scenario: Successful User Login + Given I am on the login page + When I enter valid credentials + And I click the login button + Then I should be redirected to the home page +``` + +3. Right-click on the "Login.feature" file and choose "Generate Step Definitions." + +4. Select the class where you want to generate the step definitions or create a new class. + +### Writing the Test Code + +1. Open the step definition file corresponding to the "Login.feature" scenario. + +2. Add the following code to the step definition file: + +```csharp +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TechTalk.SpecFlow; + +namespace YourNamespace +{ + [Binding] + public class LoginSteps + { + private IWebDriver driver; + + [Given(@"I am on the login page")] + public void GivenIAmOnTheLoginPage() + { + driver = new ChromeDriver(); + driver.Navigate().GoToUrl("http://localhost:3000/login"); + } + + [When(@"I enter valid credentials")] + public void WhenIEnterValidCredentials() + { + // Enter valid credentials in the login fields here + var usernameField = driver.FindElement(By.Id("username")); + usernameField.SendKeys("yourusername"); + + var passwordField = driver.FindElement(By.Id("password")); + passwordField.SendKeys("yourpassword"); + } + + [When(@"I click the login button")] + public void WhenIClickTheLoginButton() + { + var loginButton = driver.FindElement(By.Id("login-button")); + loginButton.Click(); + } + + [Then(@"I should be redirected to the home page")] + public void ThenIShouldBeRedirectedToTheHomePage() + { + Assert.AreEqual("http://localhost:3000/", driver.Url); + } + + [AfterScenario] + public void AfterScenario() + { + driver.Quit(); + } + } +} +``` + +### Running the Test + +1. Build your ReqnRoll project to compile the code. + +2. In Visual Studio, open the "Test Explorer" window. + +3. Click the "Run All Tests" button to execute the authentication test. diff --git a/e-suite.Automation.UITests/azure-pipelines.yml b/e-suite.Automation.UITests/azure-pipelines.yml new file mode 100644 index 0000000..e8b5218 --- /dev/null +++ b/e-suite.Automation.UITests/azure-pipelines.yml @@ -0,0 +1,86 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(postfix)$(branchName) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: ubuntu-latest # ubuntu-latest - set to windows-latest or another Windows vmImage for Windows builds + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + branchName: '' + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}: + branchName: $[ replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-' ) ] + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}: + branchName: $[ replace(replace(variables['System.PullRequest.TargetBranch'], 'refs/heads/', ''), '/', '-' ) ] + + ${{ if eq(variables['branchName'], '') }}: + postfix: '' + ${{ else }}: + postfix: '-' + +steps: +- task: UseDotNet@2 + displayName: 'Set .net core version' + inputs: + version: '9.0.x' + +- task: DotNetCoreCLI@2 + displayName: 'Nuget Restore' + inputs: + command: 'restore' + feedsToUse: config + projects: '**/*.csproj' + nugetConfigPath: nuget.config + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--configuration $(buildConfiguration)' + displayName: 'dotnet build $(buildConfiguration)' + +#Not going to run the tests in the build pipeline, they will be publishes as an artifact, then executed as part of the release pipeline. +# - task: DotNetCoreCLI@2 +# displayName: 'Run Tests' +# continueOnError: true +# inputs: +# command: test +# projects: '**/*/*.csproj' +# arguments: '--configuration $(buildConfiguration)' + +# task: SpecFlowPlus@0 +# continueOnError: true +# inputs: +# generatorSource: 'TestAssembly' +# testAssemblyFilePath: '**/bin/**/ESuite.UI.E2E.dll' +# projectName: 'E-suite' +# testExecutionJson: '**/TestExecution.json' +# projectLanguage: 'en' +# workItemUrlTemplate: 'https://sunbranding.visualstudio.com/e-suite/_workitems/edit/{id}' + +- task: DotNetCoreCLI@2 + displayName: 'Publish ESuite.UI.E2E' + inputs: + command: publish + projects: '**/*.csproj' + publishWebProjects: false + arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)' + zipAfterPublish: false + +- task: PublishPipelineArtifact@1 + displayName: 'Publish' + inputs: + targetPath: $(Build.ArtifactStagingDirectory) + artifactName: 'build' + artifactType: 'pipeline' \ No newline at end of file diff --git a/e-suite.Automation.UITests/nuget.config b/e-suite.Automation.UITests/nuget.config new file mode 100644 index 0000000..cc8183d --- /dev/null +++ b/e-suite.Automation.UITests/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Core/.gitattributes b/e-suite.Core/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Core/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Core/.gitignore b/e-suite.Core/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Core/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Core/.runsettings b/e-suite.Core/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Core/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Core/README.md b/e-suite.Core/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Core/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Core/azure-pipelines.yml b/e-suite.Core/azure-pipelines.yml new file mode 100644 index 0000000..5f33ecb --- /dev/null +++ b/e-suite.Core/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'eSuite.Core/eSuite.Core.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core.UnitTests/GeneralIdRefUnitTests.cs b/e-suite.Core/eSuite.Core.UnitTests/GeneralIdRefUnitTests.cs new file mode 100644 index 0000000..82af116 --- /dev/null +++ b/e-suite.Core/eSuite.Core.UnitTests/GeneralIdRefUnitTests.cs @@ -0,0 +1,340 @@ +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace eSuite.Core.UnitTests +{ + [TestFixture] + public class GeneralIdRefUnitTests + { + [Test] + public void GeneralIdRef_WhenHaveGuid_CanSetValue() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + + //Act + var generalIdRef = new GeneralIdRef + { + Guid = testGuid + }; + + //Assert + Assert.That(generalIdRef.Guid, Is.EqualTo(testGuid)); + } + + [Test] + public void GeneralIdRef_WhenHaveId_CanSetValue() + { + //Arrange + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId + }; + + //Assert + Assert.That(generalIdRef.Id, Is.EqualTo(expectedId)); + } + + [Test] + public void GeneralIdRef_WhenHaveGuidAndId_CanSetValues() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + //Assert + Assert.That(generalIdRef.Id, Is.EqualTo(expectedId)); + Assert.That(generalIdRef.Guid, Is.EqualTo(testGuid)); + } + + [Test] + public void GeneralIdRef_WhenTwoGeneralIdRefsHaveSameGuidAndId_AreEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenTwoGeneralIdRefsHaveSameGuidOnly_AreEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + + //Act + var generalIdRef = new GeneralIdRef + { + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Guid = testGuid + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenTwoGeneralIdRefsHaveSameIdOnly_AreEqual() + { + //Arrange + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenFirstSuppliesBothButSecondOnlyId_AreEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId, + Guid = null + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenFirstSuppliesBothButSecondOnlyGuid_AreEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = null, + Guid = testGuid + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenFirstSuppliesIdAndSecondBoth_AreEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = null + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenFirstSuppliesGuidButSecondBoth_AreEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = null, + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public void GeneralIdRef_WhenIdsMatchButGuidsDont_AreNotEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId, + Guid = new Guid("{1352575E-F476-4268-84B8-C550B8F34355}") + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.False); + } + + [Test] + public void GeneralIdRef_WhenGuidsMatchButIdsDont_AreNotEqual() + { + //Arrange + var testGuid = new Guid("{28CC619B-0479-4F5D-87B8-EE255763A783}"); + const int expectedId = 69; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = 72, + Guid = testGuid + }; + + var generalIdRef2 = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + //Act + var result = generalIdRef2.Equals(generalIdRef); + + //Assert + Assert.That(result, Is.False); + } + + [Test] + public void GeneralIdRef_GetHashCode_ReturnsExpectedValue() + { + //Arrange + var testGuid = new Guid("135b64dd-8f99-42df-afc0-7708f76fc7a2"); + const int expectedId = 192; + + var expectedHashCode = HashCode.Combine(expectedId, testGuid); + + + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + //Act + var hashCode = generalIdRef.GetHashCode(); + + //Assert + Assert.That(hashCode, Is.EqualTo(expectedHashCode)); + } + + [Test] + public void GeneralIdRef_EqualsString_ReturnsFalse() + { + //Arrange + var testGuid = new Guid("135b64dd-8f99-42df-afc0-7708f76fc7a2"); + const int expectedId = 192; + + var generalIdRef = new GeneralIdRef + { + Id = expectedId, + Guid = testGuid + }; + + var testSubject = "string"; + //Act + var result = generalIdRef.Equals(testSubject); + + //Assert + Assert.That(result, Is.False); + } + } +} diff --git a/e-suite.Core/eSuite.Core.UnitTests/MailRequestUnitTests.cs b/e-suite.Core/eSuite.Core.UnitTests/MailRequestUnitTests.cs new file mode 100644 index 0000000..e34b7a1 --- /dev/null +++ b/e-suite.Core/eSuite.Core.UnitTests/MailRequestUnitTests.cs @@ -0,0 +1,35 @@ +using eSuite.Core.MailService; +using NUnit.Framework; + +namespace eSuite.Core.UnitTests; + +[TestFixture] +public class MailRequestUnitTests +{ + [Test] + public void NewObject_Created_PropertiesProperlyCreated() + { + //Arrange + //Act + var mailRequest = new MailRequest(); + + //Assert + Assert.That(mailRequest.To, Is.Not.Null); + Assert.That(mailRequest.EmailType, Is.Not.Null); + Assert.That(mailRequest.Parameters, Is.Not.Null); + } + + [Test] + public void MailRequest_Created_CanSetMailType() + { + //Arrange + //Act + var mailRequest = new MailRequest + { + EmailType = MailType.DisableAuthenticator + }; + + //Assert + Assert.That(mailRequest.EmailType, Is.EqualTo(MailType.DisableAuthenticator)); + } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core.UnitTests/MailTypeUnitTests.cs b/e-suite.Core/eSuite.Core.UnitTests/MailTypeUnitTests.cs new file mode 100644 index 0000000..0a87049 --- /dev/null +++ b/e-suite.Core/eSuite.Core.UnitTests/MailTypeUnitTests.cs @@ -0,0 +1,32 @@ +using eSuite.Core.MailService; +using NUnit.Framework; + +namespace eSuite.Core.UnitTests; + +[TestFixture] +public class MailTypeUnitTests +{ + [Test] + public void MailType_ConfirmEmailAddress_Is0() + { + Assert.That((int)MailType.ConfirmEmailAddress, Is.EqualTo(0)); + } + + [Test] + public void MailType_DisableAuthenticator_Is1() + { + Assert.That((int)MailType.DisableAuthenticator, Is.EqualTo(1)); + } + + [Test] + public void MailType_PasswordReset_Is2() + { + Assert.That((int)MailType.PasswordReset, Is.EqualTo(2)); + } + + [Test] + public void MailType_PasswordResetCompleted_Is3() + { + Assert.That((int)MailType.PasswordResetCompleted, Is.EqualTo(3)); + } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core.UnitTests/UtcClockUnitTests.cs b/e-suite.Core/eSuite.Core.UnitTests/UtcClockUnitTests.cs new file mode 100644 index 0000000..b7b822b --- /dev/null +++ b/e-suite.Core/eSuite.Core.UnitTests/UtcClockUnitTests.cs @@ -0,0 +1,30 @@ +using eSuite.Core.Clock; +using NUnit.Framework; + +namespace eSuite.Core.UnitTests; + +[TestFixture] +public class UtcClockUnitTests +{ + private UtcClock _utcClock = null!; + + [SetUp] + public void Setup() + { + _utcClock = new UtcClock(); + } + + [Test] + public void GetNow_Called_ReturnsUTCNow() + { + //Arrange + var currentDateTime = DateTimeOffset.UtcNow; + + //Act + var now = _utcClock.GetNow; + + //Assert + Assert.That(now, Is.GreaterThan(currentDateTime)); + Assert.That(now, Is.LessThan(currentDateTime.AddSeconds(1))); + } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core.UnitTests/eSuite.Core.UnitTests.csproj b/e-suite.Core/eSuite.Core.UnitTests/eSuite.Core.UnitTests.csproj new file mode 100644 index 0000000..eadfdc0 --- /dev/null +++ b/e-suite.Core/eSuite.Core.UnitTests/eSuite.Core.UnitTests.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.Core/eSuite.Core.sln b/e-suite.Core/eSuite.Core.sln new file mode 100644 index 0000000..9b1ee85 --- /dev/null +++ b/e-suite.Core/eSuite.Core.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "eSuite.Core", "eSuite.Core\eSuite.Core.csproj", "{1C69B26F-B66C-4E1D-88FA-214EEF8358A5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{F61D66C7-302F-49B4-9E06-8E5B3B9F1C19}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eSuite.Core.UnitTests", "eSuite.Core.UnitTests\eSuite.Core.UnitTests.csproj", "{A1C4EFED-D998-4CC5-B86B-26D5BD3E6CF6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1C69B26F-B66C-4E1D-88FA-214EEF8358A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C69B26F-B66C-4E1D-88FA-214EEF8358A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C69B26F-B66C-4E1D-88FA-214EEF8358A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C69B26F-B66C-4E1D-88FA-214EEF8358A5}.Release|Any CPU.Build.0 = Release|Any CPU + {A1C4EFED-D998-4CC5-B86B-26D5BD3E6CF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1C4EFED-D998-4CC5-B86B-26D5BD3E6CF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1C4EFED-D998-4CC5-B86B-26D5BD3E6CF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1C4EFED-D998-4CC5-B86B-26D5BD3E6CF6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A1C4EFED-D998-4CC5-B86B-26D5BD3E6CF6} = {F61D66C7-302F-49B4-9E06-8E5B3B9F1C19} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {07643B1F-36E3-46C7-8B9B-B3F5A59471C6} + EndGlobalSection +EndGlobal diff --git a/e-suite.Core/eSuite.Core/App.config b/e-suite.Core/eSuite.Core/App.config new file mode 100644 index 0000000..d856401 --- /dev/null +++ b/e-suite.Core/eSuite.Core/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Clock/IClock.cs b/e-suite.Core/eSuite.Core/Clock/IClock.cs new file mode 100644 index 0000000..8002a09 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Clock/IClock.cs @@ -0,0 +1,6 @@ +namespace eSuite.Core.Clock; + +public interface IClock +{ + DateTimeOffset GetNow { get; } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Clock/UtcClock.cs b/e-suite.Core/eSuite.Core/Clock/UtcClock.cs new file mode 100644 index 0000000..6cfd604 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Clock/UtcClock.cs @@ -0,0 +1,7 @@ +namespace eSuite.Core.Clock +{ + public class UtcClock : IClock + { + public DateTimeOffset GetNow => DateTimeOffset.UtcNow; + } +} diff --git a/e-suite.Core/eSuite.Core/CustomFields/FieldType.cs b/e-suite.Core/eSuite.Core/CustomFields/FieldType.cs new file mode 100644 index 0000000..5e517f9 --- /dev/null +++ b/e-suite.Core/eSuite.Core/CustomFields/FieldType.cs @@ -0,0 +1,18 @@ +namespace eSuite.Core.CustomFields; + +/// +/// The master list of possible field types for custom fields. +/// +public enum FieldType +{ + Text = 0, + Number = 1, + Boolean = 2, + Date = 3, + Time = 4, + DateTime = 5, + Sequence = 6, + FormTemplate = 7, + Glossary = 8, + Domain = 9 +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/MailService/IEmailAddress.cs b/e-suite.Core/eSuite.Core/MailService/IEmailAddress.cs new file mode 100644 index 0000000..e9ec6a4 --- /dev/null +++ b/e-suite.Core/eSuite.Core/MailService/IEmailAddress.cs @@ -0,0 +1,7 @@ +namespace eSuite.Core.MailService; + +public interface IEmailAddress +{ + string Email { get; } + string DisplayName { get; } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/MailService/IMailService.cs b/e-suite.Core/eSuite.Core/MailService/IMailService.cs new file mode 100644 index 0000000..587d2b6 --- /dev/null +++ b/e-suite.Core/eSuite.Core/MailService/IMailService.cs @@ -0,0 +1,6 @@ +namespace eSuite.Core.MailService; + +public interface IMailService +{ + Task RequestEMailAsync(MailRequest emailRequest, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/MailService/MailRequest.cs b/e-suite.Core/eSuite.Core/MailService/MailRequest.cs new file mode 100644 index 0000000..5e2d514 --- /dev/null +++ b/e-suite.Core/eSuite.Core/MailService/MailRequest.cs @@ -0,0 +1,8 @@ +namespace eSuite.Core.MailService; + +public class MailRequest +{ + public IList To { get; } = new List(); + public MailType EmailType { get; set; } + public Dictionary Parameters { get; } = new(); +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/MailService/MailType.cs b/e-suite.Core/eSuite.Core/MailService/MailType.cs new file mode 100644 index 0000000..dc2cd4f --- /dev/null +++ b/e-suite.Core/eSuite.Core/MailService/MailType.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; + +namespace eSuite.Core.MailService; + +public enum MailType +{ + [Display(Name = "Confirm Email Address")] + ConfirmEmailAddress = 0, + [Display(Name = "Disable Two Factor Authentication")] + DisableAuthenticator = 1, + [Display(Name = "Password Reset")] + PasswordReset = 2, + [Display(Name = "Confirmation password reset")] + PasswordResetCompleted = 3 +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs b/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs new file mode 100644 index 0000000..e9dd8ed --- /dev/null +++ b/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs @@ -0,0 +1,44 @@ +using System; +using System.Text.Json.Serialization; + +namespace eSuite.Core.Miscellaneous; + +/// +/// General interface that can be used to identify an item. +/// To use this, will be expected to supply the Id or Guid. +/// If both at supplied, the Id is use primarily, and the Guid can then be used as a confirmation. +/// +public class GeneralIdRef : IGeneralIdRef, IEquatable +{ + [JsonPropertyName("id")] + public long? Id { get; set; } + [JsonPropertyName("Guid")] + public Guid? Guid { get; set; } + + public bool Equals(GeneralIdRef? other) + { + if (Id == null || other?.Id == null) + { + return Nullable.Equals(Guid, other?.Guid); + } + + if (Guid == null || other?.Guid == null) + { + return Nullable.Equals(Id, other?.Id); + } + + return Nullable.Equals(Id, other?.Id) && Nullable.Equals(Guid, other?.Guid); + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == this.GetType() && Equals(obj as GeneralIdRef); + } + + public override int GetHashCode() + { + return HashCode.Combine(Id, Guid); + } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Miscellaneous/IGeneralIdRef.cs b/e-suite.Core/eSuite.Core/Miscellaneous/IGeneralIdRef.cs new file mode 100644 index 0000000..b4c3e12 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Miscellaneous/IGeneralIdRef.cs @@ -0,0 +1,12 @@ +namespace eSuite.Core.Miscellaneous; + +/// +/// General interface that can be used to identify an item. +/// To use this, will be expected to supply the Id or Guid. +/// If both at supplied, the Id is use primarily, and the Guid can then be used as a confirmation. +/// +public interface IGeneralIdRef +{ + public long? Id { get; set; } + public Guid? Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Security/HiddenAttribute.cs b/e-suite.Core/eSuite.Core/Security/HiddenAttribute.cs new file mode 100644 index 0000000..875d3d4 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Security/HiddenAttribute.cs @@ -0,0 +1,5 @@ +namespace eSuite.Core.Security; + +public class HiddenAttribute : Attribute +{ +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Security/SecurityAccess.cs b/e-suite.Core/eSuite.Core/Security/SecurityAccess.cs new file mode 100644 index 0000000..7dbcb48 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Security/SecurityAccess.cs @@ -0,0 +1,240 @@ +using System.ComponentModel.DataAnnotations; + +namespace eSuite.Core.Security; + +/// +/// This is the master list of security access rights. +/// WARNING: Do not remove items from this list EVER. +/// You may mark an item with the [Obsolete] Attribute when it is no longer in use by the rest of the source code. +/// +public enum SecurityAccess +{ + [Hidden] + [Display(Name = "Everyone", Description = "Can do something that everyone can do", GroupName = "Everyone")] + Everyone = 0, + + [Display(Name = "Add User", Description = "Able to create a new user account", GroupName = "User")] + AddUser = 1, + + [Display(Name = "Edit User", Description = "Able to modify other user accounts", GroupName = "User")] + EditUser = 2, + + [Display(Name = "Delete User", Description = "Able to deactivate a users account", GroupName = "User")] + DeleteUser = 3, + + [Display(Name = "View User", Description = "Able to view one or more user account(s)", GroupName = "User")] + ViewUser = 4, + + [Display(Name = "Resend Confirm Email", Description = "Able to resend confirm email to the user", GroupName = "User")] + ResendConfirmMail = 5, + + [Display(Name = "View Specification", Description = "Able to view one or more specification(s)", GroupName = "Specification")] + ViewSpecification = 6, + + [Display(Name = "View Template For PrintSpec", Description = "Able to view template for specification(s)", GroupName = "Specification")] + ViewTemplateForPrintSpec = 7, + + [Display(Name = "Add Specification", Description = "Able to create a new specification", GroupName = "Specification")] + AddSpecification = 8, + + [Display(Name = "Edit Specification", Description = "Able to make changes to specification", GroupName = "Specification")] + EditSpecification = 9, + + [Display(Name = "Delete Specification", Description = "Able to remove a specification", GroupName = "Specification")] + DeleteSpecification = 10, + + [Display(Name = "View Site", Description = "Able to view one or more site(s)", GroupName = "Site")] + ViewSite = 11, + + [Display(Name = "Add Site", Description = "Able to create a new site", GroupName = "Site")] + AddSite = 12, + + [Display(Name = "Edit Site", Description = "Able to make changes to a site", GroupName = "Site")] + EditSite = 13, + + [Display(Name = "Delete Site", Description = "Able to remove a site", GroupName = "Site")] + DeleteSite = 14, + + [Display(Name = "View Sequence", Description = "Able to view one or more sequence(s)", GroupName = "Sequence")] + ViewSequence = 15, + + [Display(Name = "Add Sequence", Description = "Able to create a new sequence", GroupName = "Sequence")] + AddSequence = 16, + + [Display(Name = "Edit Sequence", Description = "Able to make changes to a sequence", GroupName = "Sequence")] + EditSequence = 17, + + [Display(Name = "Delete Sequence", Description = "Able to remove a sequence", GroupName = "Sequence")] + DeleteSequence = 18, + + [Hidden] + [Display(Name = "Next Sequence Value", Description = "Able to view next sequence value", GroupName = "Sequence")] + NextSequenceValue = 19, + + [Display(Name = "View Role", Description = "Able to view one or more role(s)", GroupName = "Role")] + ViewRole = 20, + + [Display(Name = "Add Role", Description = "Able to create a new role", GroupName = "Role")] + AddRole = 21, + + [Display(Name = "Edit Role", Description = "Able to make changes to a role", GroupName = "Role")] + EditRole = 22, + + [Display(Name = "Delete Role", Description = "Able to remove a role", GroupName = "Role")] + DeleteRole = 23, + + [Display(Name = "View Role Users", Description = "Able to view one or more role user(s)", GroupName = "Role")] + ViewRoleUsers = 24, + + [Display(Name = "Add Role User", Description = "Able to add a new role user", GroupName = "Role")] + AddRoleUser = 25, + + [Display(Name = "Delete Role User", Description = "Able to remove a role user", GroupName = "Role")] + DeleteRoleUser = 26, + + [Hidden] + [Display(Name = "View Access List", Description = "Able to view access list", GroupName = "Role")] + ViewAccessList = 27, + + [Display(Name = "View Role Access", Description = "Able to view role access", GroupName = "Role")] + ViewRoleAccess = 28, + + [Display(Name = "Edit Role Access", Description = "Able to edit role access", GroupName = "Role")] + EditRoleAccess = 29, + + [Hidden] + [Display(Name = "Delete Role Access", Description = "Able to remove role access", GroupName = "Role")] + DeleteRoleAccess = 30, + + [Display(Name = "View Organisation", Description = "Able to view one or more organisation(s)", GroupName = "Organisation")] + ViewOrganisation = 31, + + [Display(Name = "Add Organisation", Description = "Able to create a new organisation", GroupName = "Organisation")] + AddOrganisation = 32, + + [Display(Name = "Edit Organisation", Description = "Able to make changes to an organisation", GroupName = "Organisation")] + EditOrganisation = 33, + + [Display(Name = "Delete Organisation", Description = "Able to remove an organisation", GroupName = "Organisation")] + DeleteOrganisation = 34, + + [Obsolete("Viewing mail template types is not a protected activity")] + [Display(Name = "View Mail Template Types", Description = "Able to view one or more mail template types", GroupName = "MailTemplate")] + ViewMailTemplateTypes = 35, + + [Hidden] + [Display(Name = "View Mail Template", Description = "Able to view one or more mail template(s)", GroupName = "MailTemplate")] + ViewMailTemplate = 36, + + [Hidden] + [Display(Name = "Add Mail Template", Description = "Able to add a new mail template", GroupName = "MailTemplate")] + AddMailTemplate = 37, + + [Display(Name = "View Glossary", Description = "Able to view one or more glossary items", GroupName = "Glossary")] + ViewGlossary = 38, + + [Display(Name = "Add Glossary", Description = "Able to create a new glossary item", GroupName = "Glossary")] + AddGlossary = 39, + + [Display(Name = "Edit Glossary", Description = "Able to make changes to a glossary item", GroupName = "Glossary")] + EditGlossary = 40, + + [Display(Name = "Delete Glossary", Description = "Able to remove a glossary item", GroupName = "Glossary")] + DeleteGlossary = 41, + + [Display(Name = "View Form Template", Description = "Able to view one or more form template(s)", GroupName = "Form")] + ViewFormTemplate = 42, + + [Display(Name = "Add Form Template", Description = "Able to create a new form template", GroupName = "Form")] + AddFormTemplate = 43, + + [Display(Name = "Edit Form Template", Description = "Able to make changes to a form template", GroupName = "Form")] + EditFormTemplate = 44, + + [Display(Name = "Delete Form Template", Description = "Able to remove a form template", GroupName = "Form")] + DeleteFormTemplate = 45, + + [Hidden] + [Display(Name = "View Form Instance", Description = "Able to view one or more form instance(s)", GroupName = "Form")] + ViewFormInstance = 46, + + [Hidden] + [Display(Name = "Add Form Instance", Description = "Able to add a new form instance", GroupName = "Form")] + AddFormInstance = 47, + + [Hidden] + [Display(Name = "Edit Form Instance", Description = "Able to make changes to a form instance", GroupName = "Form")] + EditFormInstance = 48, + + [Display(Name = "View Domain", Description = "Able to view one or more domain(s)", GroupName = "Domain")] + ViewDomain = 49, + + [Display(Name = "Add Domain", Description = "Able to create a new domain", GroupName = "Domain")] + AddDomain = 50, + + [Display(Name = "Edit Domain", Description = "Able to make changes to a domain", GroupName = "Domain")] + EditDomain = 51, + + [Display(Name = "Delete Domain", Description = "Able to remove a domain", GroupName = "Domain")] + DeleteDomain = 52, + + [Display(Name = "View Field", Description = "Able to view one or more field(s)", GroupName = "CustomField")] + ViewField = 53, + + [Display(Name = "Add Field", Description = "Able to create a new field", GroupName = "CustomField")] + AddField = 54, + + [Display(Name = "Edit Field", Description = "Able to make changes to a field", GroupName = "CustomField")] + EditField = 55, + + [Display(Name = "Delete Field", Description = "Able to remove a field", GroupName = "CustomField")] + DeleteField = 56, + + [Display(Name = "View Audit Log", Description = "Able to view one or more audit log(s)", GroupName = "AuditLog")] + ViewAuditLog = 57, + + [Display(Name = "View Blocked IP Address", Description = "Able to view one or more blocked IP addresses", GroupName = "BlockedIPAddresses")] + ViewBlockedIPAddresses = 58, + + [Display(Name = "UnBlock IP Address", Description = "Able to unblock blocked IP address", GroupName = "BlockedIPAddresses")] + UnlockIPAddress = 59, + + [Display(Name = "View Error Logs", Description = "Able to view error log(s)", GroupName = "ErrorLogs")] + ViewErrorLogs = 60, + + [Display(Name = "Get Current Email Action Url", Description = "Get the current URL for a supplied user (note this is intended to internal use only)", GroupName = "User")] + GetCurrentEmailActionUrl = 61, + + [Display(Name = "View SsoProvider details", Description = "Get the details of the SsoProviders used for single sign on", GroupName = "SsoProvider")] + ViewSsoProviders = 62, + + [Display(Name = "Add SsoProvider details", Description = "Add a new Single Sign On provider", GroupName = "SsoProvider")] + AddSsoProvider = 63, + + [Display(Name = "Edit SsoProvider details", Description = "Edit an existing Single Sign On provider", GroupName = "SsoProvider")] + EditSsoProvider = 64, + + [Display(Name = "Delete SsoProvider", Description = "Delete existing Single Sign On provider", GroupName = "SsoProvider")] + DeleteSsoProvider = 65, + + [Display(Name = "ImportGMGProfiles", Description = "ImportGMGProfiles", GroupName = "Internal Maintenance")] + ImportGMGProfiles = 66, + + [Display(Name = "ClearOldEmailActions", Description = "ClearOldEmailActions", GroupName = "Internal Maintenance")] + ClearOldEmailActions = 67, + + [Display(Name = "ClearOldPerformanceData", Description = "ClearOldPerformanceData", GroupName = "Internal Maintenance")] + ClearOldPerformanceData = 68, + + [Display(Name = "ClearOldSentinelData", Description = "ClearOldSentinelData", GroupName = "Internal Maintenance")] + ClearOldSentinelData = 69, + + [Display(Name = "ClearOldSingleUserGuids", Description = "ClearOldSingleUserGuids", GroupName = "Internal Maintenance")] + ClearOldSingleUserGuids = 70, + + [Display(Name = "ImportPrintSpecifications", Description = "ImportPrintSpecifications", GroupName = "Internal Maintenance")] + ImportPrintSpecifications = 71, + + [Display(Name = "SyncEFlowPrinterCategories", Description = "SyncEFlowPrinterCategories", GroupName = "Internal Maintenance")] + SyncEFlowPrinterCategories = 72, +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Sequences/Rollover.cs b/e-suite.Core/eSuite.Core/Sequences/Rollover.cs new file mode 100644 index 0000000..33e3015 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Sequences/Rollover.cs @@ -0,0 +1,10 @@ +namespace eSuite.Core.Sequences +{ + public enum Rollover + { + Continuous, + Year, + Month, + Day + } +} diff --git a/e-suite.Core/eSuite.Core/Workflow/BudgetOption.cs b/e-suite.Core/eSuite.Core/Workflow/BudgetOption.cs new file mode 100644 index 0000000..c3175ee --- /dev/null +++ b/e-suite.Core/eSuite.Core/Workflow/BudgetOption.cs @@ -0,0 +1,8 @@ +namespace eSuite.Core.Workflow; + +public enum BudgetOption +{ + DoNotShow, + ShowOnly, + ShowAndEdit +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Workflow/Priority.cs b/e-suite.Core/eSuite.Core/Workflow/Priority.cs new file mode 100644 index 0000000..458129c --- /dev/null +++ b/e-suite.Core/eSuite.Core/Workflow/Priority.cs @@ -0,0 +1,8 @@ +namespace eSuite.Core.Workflow; + +public enum Priority +{ + Low, + Normal, + High +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Workflow/Raci.cs b/e-suite.Core/eSuite.Core/Workflow/Raci.cs new file mode 100644 index 0000000..4e5f836 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Workflow/Raci.cs @@ -0,0 +1,9 @@ +namespace eSuite.Core.Workflow; + +public enum Raci +{ + Responsible, + Accountable, + Consulted, + Informed +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Workflow/TaskState.cs b/e-suite.Core/eSuite.Core/Workflow/TaskState.cs new file mode 100644 index 0000000..f9e9931 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Workflow/TaskState.cs @@ -0,0 +1,17 @@ +using System.ComponentModel; + +namespace eSuite.Core.Workflow; + +public enum TaskState +{ + [Description("The task is waiting to start")] + Pending, + [Description("The task has been cancelled")] + Cancelled, + [Description("The task is active for user/system interaction and processing")] + Active, + [Description("The active portion of the task has finished and the task is ready to complete")] + ReadyToComplete, + [Description("The task has been completed")] + Completed +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/Workflow/WorkflowState.cs b/e-suite.Core/eSuite.Core/Workflow/WorkflowState.cs new file mode 100644 index 0000000..e184627 --- /dev/null +++ b/e-suite.Core/eSuite.Core/Workflow/WorkflowState.cs @@ -0,0 +1,17 @@ +using System.ComponentModel; + +namespace eSuite.Core.Workflow; + +public enum WorkflowState +{ + [Description("The workflow has not yet started")] + Pending, + [Description("The workflow has been cancelled abd wukk bit be processed")] + Cancelled, + [Description("The workflow is currently active for user/system interaction and processing")] + Active, + [Description("The active portion of the workflow has finished and the workflow is ready to complete")] + ReadyToComplete, + [Description("Processing of this item has finished the ")] + Completed +} \ No newline at end of file diff --git a/e-suite.Core/eSuite.Core/eSuite.Core.csproj b/e-suite.Core/eSuite.Core/eSuite.Core.csproj new file mode 100644 index 0000000..8769330 --- /dev/null +++ b/e-suite.Core/eSuite.Core/eSuite.Core.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + enable + enable + + + + + + + + diff --git a/e-suite.Core/nuget.config b/e-suite.Core/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Core/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.CustomerApi/.gitattributes b/e-suite.CustomerApi/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.CustomerApi/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.CustomerApi/.gitignore b/e-suite.CustomerApi/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.CustomerApi/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.CustomerApi/README.md b/e-suite.CustomerApi/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.CustomerApi/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.CustomerApi/azure-pipelines.yml b/e-suite.CustomerApi/azure-pipelines.yml new file mode 100644 index 0000000..0a5823a --- /dev/null +++ b/e-suite.CustomerApi/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.CustomerApi/e-suite.CustomerApi.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi.sln b/e-suite.CustomerApi/e-suite.CustomerApi.sln new file mode 100644 index 0000000..7e17251 --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34316.72 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.CustomerApi", "e-suite.CustomerApi\e-suite.CustomerApi.csproj", "{A115639A-35DC-425A-84D9-DA78928AEE6C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A115639A-35DC-425A-84D9-DA78928AEE6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A115639A-35DC-425A-84D9-DA78928AEE6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A115639A-35DC-425A-84D9-DA78928AEE6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A115639A-35DC-425A-84D9-DA78928AEE6C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5C5316D4-1FA4-4B8F-A235-FB1308216E1B} + EndGlobalSection +EndGlobal diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/ApiSettings.cs b/e-suite.CustomerApi/e-suite.CustomerApi/ApiSettings.cs new file mode 100644 index 0000000..8647f37 --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/ApiSettings.cs @@ -0,0 +1,32 @@ +using e_suite.CustomerApi.exceptions; + +namespace e_suite.CustomerApi; + +public sealed class ApiSettings +{ + private static readonly Lazy LazyInstance = new(() => new ApiSettings()); + private string _token = ""; + + private ApiSettings() + { + + } + + public static ApiSettings Instance => LazyInstance.Value; + + public Uri BaseUrl { get; set; } = new Uri("https://localhost:7066/api/"); + + public string Token + { + get + { + if (string.IsNullOrWhiteSpace(_token)) + { + throw new NotLoggedInException("You must be logged in to call this API Function"); + } + + return _token; + } + set => _token = value; + } +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/Authentication.cs b/e-suite.CustomerApi/e-suite.CustomerApi/Authentication.cs new file mode 100644 index 0000000..a9ddc1a --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/Authentication.cs @@ -0,0 +1,24 @@ +using System.Text.Json; +using System.Text; +using e_suite.API.Common.models; +using e_suite.CustomerApi.Helper; +using e_suite.CustomerApi.models; + +namespace e_suite.CustomerApi; + +public class Authentication +{ + public async Task Login(Login login) + { + var client = HttpHelper.CreateClient(); + + client.BaseAddress = ApiSettings.Instance.BaseUrl; + + var json = JsonSerializer.Serialize(login); + var body = new StringContent(json, Encoding.UTF8, "application/json"); + var response = await client.PostAsync("Authentication/login", body); + + var result = JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync()); + ApiSettings.Instance.Token = result.Token; + } +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/Domain.cs b/e-suite.CustomerApi/e-suite.CustomerApi/Domain.cs new file mode 100644 index 0000000..6bc5fba --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/Domain.cs @@ -0,0 +1,23 @@ +using System.Net.Http.Headers; +using System.Text.Json; +using e_suite.API.Common.models; +using e_suite.CustomerApi.Helper; +using e_suite.CustomerApi.models; + +namespace e_suite.CustomerApi; + +public class Domain +{ + public async Task> GetDomains() + { + var client = HttpHelper.CreateClient(); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiSettings.Instance.Token); + client.BaseAddress = ApiSettings.Instance.BaseUrl; + + var response = await client.GetAsync("Domain/domains?page=0"); + var responseString = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize>(responseString); + + return result.Data; + } +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/User.cs b/e-suite.CustomerApi/e-suite.CustomerApi/User.cs new file mode 100644 index 0000000..c57503c --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/User.cs @@ -0,0 +1,28 @@ +using e_suite.API.Common.models; +using e_suite.CustomerApi.Helper; +using System.Net.Http.Headers; +using System.Text; +using System.Text.Json; + +namespace e_suite.CustomerApi; + +public class User +{ + public async Task CreateUser(UserRegistration userRegistration) + { + var client = HttpHelper.CreateClient(); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiSettings.Instance.Token); + client.BaseAddress = ApiSettings.Instance.BaseUrl; + + var json = JsonSerializer.Serialize(userRegistration); + var body = new StringContent(json, Encoding.UTF8, "application/json"); + var response = await client.PostAsync("User/user", body); + + if (response.IsSuccessStatusCode) + return; + + var responseBody = await response.Content.ReadAsStringAsync(); + + throw new Exception(responseBody); + } +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/e-suite.CustomerApi.csproj b/e-suite.CustomerApi/e-suite.CustomerApi/e-suite.CustomerApi.csproj new file mode 100644 index 0000000..55caac6 --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/e-suite.CustomerApi.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + e_suite.CustomerApi + enable + enable + + + + + + + diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/exceptions/NotLoggedInException.cs b/e-suite.CustomerApi/e-suite.CustomerApi/exceptions/NotLoggedInException.cs new file mode 100644 index 0000000..559e2a3 --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/exceptions/NotLoggedInException.cs @@ -0,0 +1,9 @@ +namespace e_suite.CustomerApi.exceptions; + +public class NotLoggedInException : Exception +{ + public NotLoggedInException(string message) : base(message) + { + + } +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/helper/HttpHelper.cs b/e-suite.CustomerApi/e-suite.CustomerApi/helper/HttpHelper.cs new file mode 100644 index 0000000..df0f19e --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/helper/HttpHelper.cs @@ -0,0 +1,14 @@ +namespace e_suite.CustomerApi.Helper; + +internal static class HttpHelper +{ + public static HttpClient CreateClient() + { + var handler = new HttpClientHandler(); + handler.ClientCertificateOptions = ClientCertificateOption.Manual; + handler.ServerCertificateCustomValidationCallback = + (httpRequestMessage, cert, cetChain, policyErrors) => { return true; }; //This should return true for Self signed certificates, or real certificates. + + return new HttpClient(handler); + } +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/models/Paginated.cs b/e-suite.CustomerApi/e-suite.CustomerApi/models/Paginated.cs new file mode 100644 index 0000000..c4a2267 --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/models/Paginated.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace e_suite.CustomerApi.models; + +public class Paginated +{ + [JsonPropertyName("count")] + public long Count { get; set; } + + [JsonPropertyName("pageSize")] + public int PageSize { get; set; } + + [JsonPropertyName("page")] + public int Page { get; set; } + + [JsonIgnore] + public int TotalPages => Convert.ToInt32(Math.Ceiling(Count / Convert.ToDecimal(PageSize))); + + [JsonPropertyName("data")] + public List Data { get; set; } = new List(); +} \ No newline at end of file diff --git a/e-suite.CustomerApi/e-suite.CustomerApi/models/SuccessfulLogin.cs b/e-suite.CustomerApi/e-suite.CustomerApi/models/SuccessfulLogin.cs new file mode 100644 index 0000000..d4ee3c9 --- /dev/null +++ b/e-suite.CustomerApi/e-suite.CustomerApi/models/SuccessfulLogin.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace e_suite.CustomerApi.models; + +public class SuccessfulLogin +{ + /// + /// Title of the message stating that the login was successful. + /// + [JsonPropertyName("title")] + [Required] + public string Title { get; set; } = string.Empty; + + /// + /// The token to include in the bearer header to allow access to secure API calls. + /// + [JsonPropertyName("token")] + [Required] + public string Token { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.CustomerApi/nuget.config b/e-suite.CustomerApi/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.CustomerApi/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Database.Audit/.gitattributes b/e-suite.Database.Audit/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Database.Audit/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Database.Audit/.gitignore b/e-suite.Database.Audit/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Database.Audit/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Database.Audit/.runsettings b/e-suite.Database.Audit/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Database.Audit/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Database.Audit/README.md b/e-suite.Database.Audit/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Database.Audit/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Database.Audit/azure-pipelines.yml b/e-suite.Database.Audit/azure-pipelines.yml new file mode 100644 index 0000000..9eb6eed --- /dev/null +++ b/e-suite.Database.Audit/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Database.Audit/e-suite.Database.Audit.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/AddRowUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/AddRowUnitTests.cs new file mode 100644 index 0000000..0185bb9 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/AddRowUnitTests.cs @@ -0,0 +1,678 @@ +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.UnitTests.Helpers; +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class AddRowUnitTests : AuditEngineCoreTestBase +{ + [Test] + public async Task AddRow_WhenTableMarkedNoAudit_DoesNotCreateAuditEntry() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "If this gets inserted, something went wrong" + }; + + //Act + var generalComment = new GeneralComment + { + Comment = "This is a test" + }; + + testDBContext.GeneralComments.Add(generalComment); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.GeneralComments.Count(), Is.EqualTo(1)); + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(0)); + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(0)); + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_WhenTableNotMarkedNoAudit_CreatesAuditEntry(string auditComment) + { + //Arrange + TestNow = new DateTimeOffset(2022, 06, 15, 18, 50, 52, 32, TimeSpan.Zero); + + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var recordedComment = new RecordedComment + { + Id = 42, + Comment = "This is a test" + }; + + //Act + testDBContext.RecordedComments.Add(recordedComment); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.RecordedComments.Count(), Is.EqualTo(1)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.DateTime, Is.EqualTo(TestNow)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo( $"{{\"{nameof(recordedComment.Id)}\":{{\"NewValue\":{recordedComment.Id}}},\"{nameof(recordedComment.Comment)}\":{{\"NewValue\":\"{recordedComment.Comment}\"}}}}" )); + + //Ensure that the AuditEntry is saved properly. + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + var auditEntry = testDBContext.AuditEntries.First(); + Assert.That(auditEntry.Id, Is.EqualTo(1)); + Assert.That(auditEntry.EntityName, Is.EqualTo(typeof(RecordedComment).FullName)); + Assert.That(auditEntry.DisplayName, Is.EqualTo(string.Empty)); + Assert.That(auditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(auditEntry.PrimaryKey, Is.EqualTo("{\"Id\":42}")); + Assert.That(auditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task AddRow_SaveChangesNoAuditCalled_AuditingBypassedCompletely() + { + //Arrange + //Act + var recordedComment = new RecordedComment + { + Comment = "This is a test" + }; + + testDBContext.RecordedComments.Add(recordedComment); + await testDBContext.NoAuditSaveChangesAsync(); + + //Assert + Assert.That(testDBContext.RecordedComments.Count(), Is.EqualTo(1)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(0)); + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(0)); + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_WhenFieldHasAuditName_DisplayNameFilledIn(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + //Act + var entryWithName = new EntryWithName + { + Name = "TestName" + }; + + testDBContext.EntriesWithName.Add(entryWithName); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + var auditEntry = testDBContext.AuditEntries.First(); + Assert.That(auditEntry.DisplayName, Is.EqualTo(entryWithName.Name)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_WhenFieldHasRedactAudit_FieldValueRedacted(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + //Act + var secretValue = new SecretValue + { + Id = 10, + Name = "TestName", + Secret = "I'm not telling you" + }; + + testDBContext.SecretValues.Add(secretValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo($"{{\"{nameof(SecretValue.Id)}\":{{\"NewValue\":{secretValue.Id}}},\"{nameof(secretValue.Name)}\":{{\"NewValue\":\"{secretValue.Name}\"}},\"{nameof(secretValue.Secret)}\":{{\"NewValue\":\"\"}}}}")); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_WhenKeyFieldNotAssigned_FieldNotIncludedInAuditRecord(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + //Act + var secretValue = new SecretValue + { + Name = "TestName", + Secret = "I'm not telling you" + }; + + testDBContext.SecretValues.Add(secretValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo($"{{\"{nameof(secretValue.Name)}\":{{\"NewValue\":\"{secretValue.Name}\"}},\"{nameof(secretValue.Secret)}\":{{\"NewValue\":\"\"}}}}")); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_WhenFieldHasAuditParentWithNullId_OnlyPrimaryAuditEntrySaved(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + //Act + var childValue = new ChildValue + { + Name = "TestName", + ParentId = null + }; + + testDBContext.ChildValues.Add(childValue); + + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(ChildValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(childValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{childValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_ChildValueHasParent_BothParentAndChildKeysAreRecorded(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var parentValue = new ParentValue + { + Id = 100, + Name = "Parent Entry" + }; + + testDBContext.ParentValues.Add(parentValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var childValue = new ChildValue + { + Id = 1000, + Name = "TestName", + ParentId = parentValue.Id + }; + + testDBContext.ChildValues.Add(childValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(2)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(ChildValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(childValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{childValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var parentAuditEntry = auditEntries[1]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(2)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(ParentValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(parentValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{parentValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(1)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_WhenFieldHasAuditParentWithId_OnlyPrimaryAndParentIdsEntered(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var grandParentValue = new GrandParentValue + { + Id = 10000, + Name = "GrandParent Entry" + }; + + var parentValue = new ParentValue + { + Id = 100, + Name = "Parent Entry", + GrandParentId = grandParentValue.Id + }; + + testDBContext.GrandParentValues.Add(grandParentValue); + testDBContext.ParentValues.Add(parentValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var childValue = new ChildValue + { + Id = 1000, + Name = "TestName", + ParentId = parentValue.Id + }; + + testDBContext.ChildValues.Add(childValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(3)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(ChildValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(childValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{childValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var parentAuditEntry = auditEntries[1]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(2)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(ParentValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(parentValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{parentValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + var grandParentAuditEntry = auditEntries[2]; + Assert.That(grandParentAuditEntry.Id, Is.EqualTo(3)); + Assert.That(grandParentAuditEntry.EntityName, Is.EqualTo(typeof(GrandParentValue).FullName)); + Assert.That(grandParentAuditEntry.DisplayName, Is.EqualTo(grandParentValue.Name)); + Assert.That(grandParentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(grandParentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{grandParentValue.Id}}}")); + Assert.That(grandParentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(2)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + + Assert.That(auditDrillHierarchies[1].ChildAuditDrillDownEntityId, Is.EqualTo(2)); + Assert.That(auditDrillHierarchies[1].ParentAuditDrillDownEntityId, Is.EqualTo(3)); + } + + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_TableHasSelfReferenceAndReferenceNull_OnlyPrimaryAndParentIdsEntered(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + //Act + var leafSimpleTreeValue = new SimpleTreeValue + { + Id = 30000, + Name = "Leaf Level item", + ParentId = null + }; + + testDBContext.SimpleTreeValues.Add(leafSimpleTreeValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.SimpleTreeValues.Count(), Is.EqualTo(1)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(SimpleTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafSimpleTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafSimpleTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_TableHasSelfReferenceWithSingleAncestor_BothValuesAreRecorded(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var rootSimpleTreeValue = new SimpleTreeValue + { + Id = 3000, + Name = "Leaf Level item", + ParentId = null + }; + + testDBContext.SimpleTreeValues.Add(rootSimpleTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var leafSimpleTreeValue = new SimpleTreeValue + { + Id = 30000, + Name = "Leaf Level item", + ParentId = rootSimpleTreeValue.Id + }; + + testDBContext.SimpleTreeValues.Add(leafSimpleTreeValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.SimpleTreeValues.Count(), Is.EqualTo(2)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(2)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(SimpleTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafSimpleTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafSimpleTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var parentAuditEntry = auditEntries[1]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(2)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(SimpleTreeValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(rootSimpleTreeValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{rootSimpleTreeValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(1)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + } + + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_TableHasSelfReferenceWithTwoAncestors_BothValuesAreRecorded(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var rootSimpleTreeValue = new SimpleTreeValue + { + Id = 300, + Name = "Leaf Level item", + ParentId = null + }; + + + var level1SimpleTreeValue = new SimpleTreeValue + { + Id = 3000, + Name = "Level 1 item", + ParentId = rootSimpleTreeValue.Id + }; + + testDBContext.SimpleTreeValues.Add(rootSimpleTreeValue); + testDBContext.SimpleTreeValues.Add(level1SimpleTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var leafSimpleTreeValue = new SimpleTreeValue + { + Id = 30000, + Name = "Leaf Level item", + ParentId = level1SimpleTreeValue.Id + }; + + testDBContext.SimpleTreeValues.Add(leafSimpleTreeValue); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.SimpleTreeValues.Count(), Is.EqualTo(3)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(3)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(SimpleTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafSimpleTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafSimpleTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var parentAuditEntry = auditEntries[1]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(2)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(SimpleTreeValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(level1SimpleTreeValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{level1SimpleTreeValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + var grandParentAuditEntry = auditEntries[2]; + Assert.That(grandParentAuditEntry.Id, Is.EqualTo(3)); + Assert.That(grandParentAuditEntry.EntityName, Is.EqualTo(typeof(SimpleTreeValue).FullName)); + Assert.That(grandParentAuditEntry.DisplayName, Is.EqualTo(rootSimpleTreeValue.Name)); + Assert.That(grandParentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(grandParentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{rootSimpleTreeValue.Id}}}")); + Assert.That(grandParentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(2)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + + Assert.That(auditDrillHierarchies[1].ChildAuditDrillDownEntityId, Is.EqualTo(2)); + Assert.That(auditDrillHierarchies[1].ParentAuditDrillDownEntityId, Is.EqualTo(3)); + } + + [TestCase("")] + public async Task AddRow_RowContainsEnum_EnumValueAuditedProperly(string auditComment) + { + //Arrange + TestNow = new DateTimeOffset(2022, 06, 15, 18, 50, 52, 32, TimeSpan.Zero); + + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var recordedComment = new TableWithEnums + { + Id = 1, + RawEnum = TestEnum.Item1 + }; + + //Act + testDBContext.TableWithEnums.Add(recordedComment); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.TableWithEnums.Count(), Is.EqualTo(1)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Fields, Is.EqualTo($"{{\"{nameof(recordedComment.Id)}\":{{\"NewValue\":{recordedComment.Id}}},\"{nameof(recordedComment.RawEnum)}\":{{\"NewValue\":0,\"NewDisplayName\":\"Item1\"}}}}")); + } + + [TestCase("")] + public async Task AddRow_RowContainsEnumWithDisplayValue_EnumValueAuditedProperly(string auditComment) + { + //Arrange + TestNow = new DateTimeOffset(2022, 06, 15, 18, 50, 52, 32, TimeSpan.Zero); + + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var recordedComment = new TableWithDisplayEnums + { + Id = 1 + }; + + //Act + testDBContext.TableWithDisplayEnums.Add(recordedComment); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.TableWithDisplayEnums.Count(), Is.EqualTo(1)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + + Assert.That(auditDetail.Fields, Is.EqualTo($"{{\"{nameof(recordedComment.Id)}\":{{\"NewValue\":{recordedComment.Id}}},\"{nameof(recordedComment.DisplayEnum)}\":{{\"NewValue\":0,\"NewDisplayName\":\"Item 1\"}}}}")); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/AdvancedUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/AdvancedUnitTests.cs new file mode 100644 index 0000000..8301eef --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/AdvancedUnitTests.cs @@ -0,0 +1,112 @@ +using e_suite.Database.Audit.UnitTests.Helpers; +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class AdvancedUnitTests : AuditEngineCoreTestBase +{ + [TestCase("")] + [TestCase("Test Comment")] + public async Task CreatingAuditRecord_WhenItemDoesNotHaveParentLoaded_ParentIsLoadedOnDemand(string auditComment) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var rootSimpleTreeValue = new SimpleTreeValue + { + Name = "Leaf Level item", + ParentId = null + }; + + testDBContext.SimpleTreeValues.Add(rootSimpleTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + var level1SimpleTreeValue = new SimpleTreeValue + { + Name = "Level 1 item", + ParentId = rootSimpleTreeValue.Id + }; + + testDBContext.SimpleTreeValues.Add(level1SimpleTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + var level2SimpleTreeValue = new SimpleTreeValue + { + Name = "Leaf Level item", + ParentId = level1SimpleTreeValue.Id + }; + + testDBContext.SimpleTreeValues.Add(level2SimpleTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var secondDbContext = testDbContextFactory.CreateContext(_clockMock.Object); + + var itemUnderTest = secondDbContext.SimpleTreeValues + .Single(x => x.Id == level2SimpleTreeValue.Id); + itemUnderTest.Name = "A Change"; + + Assert.That(itemUnderTest.Parent, Is.Null); //should be null + + await secondDbContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(itemUnderTest.Parent, Is.Not.Null); + Assert.That(itemUnderTest.Parent.Id, Is.EqualTo(level1SimpleTreeValue.Id)); + + Assert.That(itemUnderTest.Parent.Parent, Is.Not.Null); + Assert.That(itemUnderTest.Parent.Parent.Id, Is.EqualTo(rootSimpleTreeValue.Id)); + + Assert.That(itemUnderTest.Parent.Parent.Parent, Is.Null); + } + + [Test] + public async Task CreatingAuditRecord_WhenAuditNameNeedsForeignKeyResolved_ParentIsLoadedOnDemand() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = "" + }; + + var grandParentValue = new GrandParentValue + { + Name = "Grandparent Value", + Id = 100 + }; + + testDBContext.GrandParentValues.Add(grandParentValue); + await testDBContext.NoAuditSaveChangesAsync(); + + var linkedEntryWithName = new LinkedEntryWithName + { + Id = 50, + LinkId = grandParentValue.Id + }; + testDBContext.LinkedEntryWithName.Add(linkedEntryWithName); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var secondDbContext = testDbContextFactory.CreateContext(_clockMock.Object); + + var itemUnderTest = secondDbContext.LinkedEntryWithName + .Single(x => x.Id == linkedEntryWithName.Id); + + Assert.That(itemUnderTest.GrandParentValue, Is.Null); //should be null + + itemUnderTest.SomethingToChange = "A new Value"; + + await secondDbContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(itemUnderTest.GrandParentValue, Is.Not.Null); + Assert.That(itemUnderTest.GrandParentValue.Id, Is.EqualTo(linkedEntryWithName.LinkId)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/CreateAuditEngineCoreUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/CreateAuditEngineCoreUnitTests.cs new file mode 100644 index 0000000..2ecbdd1 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/CreateAuditEngineCoreUnitTests.cs @@ -0,0 +1,17 @@ +using e_suite.Database.Audit.UnitTests.Helpers; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class CreateAuditEngineCoreUnitTests : AuditEngineCoreTestBase +{ + [Test] + public void AuditEngineCore_Create_DoesNotThrow() + { + //Arrange + //Act + //Assert + Assert.That(testDBContext, Is.Not.Null); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/EditRowUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/EditRowUnitTests.cs new file mode 100644 index 0000000..b0ffcfb --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/EditRowUnitTests.cs @@ -0,0 +1,341 @@ +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.UnitTests.Helpers; +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class EditRowUnitTests : AuditEngineCoreTestBase +{ + [Test] + public async Task UpdateRow_TableNotAudited_NoAuditRecordCreated() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new GeneralComment + { + Id = 30000, + Comment = "Original Comment", + }; + + testDBContext.GeneralComments.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.GeneralComments.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Comment = "Modified Comment"; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(0)); + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(0)); + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task UpdateRow_TableAudited_AuditRecordIsCreated() + { + //Arrange + const string unmodifiedName = "Leaf Level item"; + const string modifiedName = "Modified Name"; + + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = unmodifiedName, + Test = "Test Value" + }; + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Name = modifiedName; + + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Update.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo($"{{\"Name\":{{\"OldValue\":\"{unmodifiedName}\",\"NewValue\":\"{modifiedName}\"}}}}")); + + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(modifiedName)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task UpdateRow_MultipleFieldsEdited_AuditRecordIsCreated() + { + //Arrange + const string unmodifiedName = "Leaf Level item"; + const string modifiedName = "Modified Name"; + + const string unmodifiedTestValue = "Test Value"; + const string modifiedTestValue = "Altered Test Value"; + + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = unmodifiedName, + Test = unmodifiedTestValue + }; + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Name = modifiedName; + itemToEdit.Test = modifiedTestValue; + + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Update.ToString())); + Assert.That(auditDetail.Fields, + Is.EqualTo($"{{\"Name\":{{\"OldValue\":\"{unmodifiedName}\",\"NewValue\":\"{modifiedName}\"}},\"Test\":{{\"OldValue\":\"{unmodifiedTestValue}\",\"NewValue\":\"{modifiedTestValue}\"}}}}")); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(modifiedName)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task UpdateRow_WhenUpdatingSecretValue_AuditRecordIsMarkedAsRedacted() + { + //Arrange + const string originalSecret = "I've forgotten"; + const string modifiedSecret = "I'm not telling you"; + + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new SecretValue + { + Id = 30000, + Name = "Test secret", + Secret = originalSecret + }; + + testDBContext.SecretValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.SecretValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Secret = modifiedSecret; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Update.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo($"{{\"Secret\":{{\"OldValue\":\"\",\"NewValue\":\"\"}}}}")); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(SecretValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task UpdateRow_WhenChangingParentIdInChildValueFromNull_NewNameIsPopulatedCorrectly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + testDBContext.ParentValues.Add(new ParentValue + { + Id = 10, + Name = "Parent 10", + }); + + testDBContext.ParentValues.Add(new ParentValue + { + Id = 20, + Name = "Parent 20", + }); + + testDBContext.ChildValues.Add(new ChildValue + { + Id = 1, + Name = "ChildValue", + ParentId = null + }); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + + var childValue = testDBContext.ChildValues.Single(x => x.Id == 1); + childValue.ParentId = 20; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var auditEntries = testDBContext.AuditEntries.Where( x => x.IsPrimary == true).ToList(); + Assert.That(auditEntries.Count, Is.EqualTo(1)); + var entry = auditEntries.First(); + Assert.That(entry.AuditLog.Fields, Is.EqualTo("{\"ParentId\":{\"NewValue\":20,\"NewDisplayName\":\"Parent 20\"}}")); + } + + [Test] + public async Task UpdateRow_WhenChangingParentIdInChildValueChanged_OldNameAndNewNamePopulatedCorrectly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + testDBContext.ParentValues.Add(new ParentValue + { + Id = 10, + Name = "Parent 10", + }); + + testDBContext.ParentValues.Add(new ParentValue + { + Id = 20, + Name = "Parent 20", + }); + + testDBContext.ChildValues.Add(new ChildValue + { + Id = 1, + Name = "ChildValue", + ParentId = 10 + }); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + + var childValue = testDBContext.ChildValues.Single(x => x.Id == 1); + childValue.ParentId = 20; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var auditEntries = testDBContext.AuditEntries.Where(x => x.IsPrimary == true).ToList(); + Assert.That(auditEntries.Count, Is.EqualTo(1)); + var entry = auditEntries.First(); + Assert.That(entry.AuditLog.Fields, Is.EqualTo("{\"ParentId\":{\"OldValue\":10,\"OldDisplayName\":\"Parent 10\",\"NewValue\":20,\"NewDisplayName\":\"Parent 20\"}}")); + } + + [Test] + public async Task UpdateRow_WhenChangingParentIdInChildValueChangedToNull_OldNameAndNewNamePopulatedCorrectly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + testDBContext.ParentValues.Add(new ParentValue + { + Id = 10, + Name = "Parent 10", + }); + + testDBContext.ParentValues.Add(new ParentValue + { + Id = 20, + Name = "Parent 20", + }); + + testDBContext.ChildValues.Add(new ChildValue + { + Id = 1, + Name = "ChildValue", + ParentId = 10 + }); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + + var childValue = testDBContext.ChildValues.Single(x => x.Id == 1); + childValue.ParentId = null; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var auditEntries = testDBContext.AuditEntries.Where(x => x.IsPrimary == true).ToList(); + Assert.That(auditEntries.Count, Is.EqualTo(1)); + var entry = auditEntries.First(); + Assert.That(entry.AuditLog.Fields, Is.EqualTo("{\"ParentId\":{\"OldValue\":10,\"OldDisplayName\":\"Parent 10\"}}")); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/HardDeleteUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/HardDeleteUnitTests.cs new file mode 100644 index 0000000..a262f72 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/HardDeleteUnitTests.cs @@ -0,0 +1,64 @@ +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.UnitTests.Helpers; +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class HardDeleteUnitTests : AuditEngineCoreTestBase +{ + [TestCase("")] + [TestCase("Test Comment")] + public async Task AddRow_TableHasSelfReferenceAndReferenceNull_AuditForHardDeleteRecorded(string auditComment) + { + //Arrrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = auditComment + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = "Leaf Level item", + }; + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + testDBContext.DeletableTreeValues.Remove(itemToEdit); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.DeletableTreeValues.Count(), Is.EqualTo(0)); + + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Purge.ToString())); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/LastUpdatedUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/LastUpdatedUnitTests.cs new file mode 100644 index 0000000..3497f69 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/LastUpdatedUnitTests.cs @@ -0,0 +1,201 @@ +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.UnitTests.Helpers; +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class LastUpdatedUnitTests : AuditEngineCoreTestBase +{ + [Test] + public async Task NewRow_WhenAdded_SetsLastUpdatedToNow() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var entry = new TableWithLastUpdated + { + Name = "TestName" + }; + + //Act + testDBContext.TableWithLastUpdateds.Add(entry); + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var editedItem = testDBContext.TableWithLastUpdateds.Single(x => x.Name == entry.Name); + + Assert.That(editedItem.LastUpdated, Is.EqualTo(TestNow)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.DateTime, Is.EqualTo(TestNow)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Create.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo("{\"Deleted\":{\"NewValue\":false},\"Name\":{\"NewValue\":\"TestName\"}}")); + + } + + [Test] + public async Task ExistingRow_WhenUpdated_SetsLastUpdatedToNow() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var entry = new TableWithLastUpdated + { + Name = "TestName" + }; + + testDBContext.TableWithLastUpdateds.Add(entry); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.TableWithLastUpdateds.Single( x => x.Name == entry.Name); + itemToEdit.Name = "Updated"; + + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var editedItem = testDBContext.TableWithLastUpdateds.Single(x => x.Name == itemToEdit.Name); + + Assert.That(editedItem.LastUpdated, Is.EqualTo(TestNow)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.DateTime, Is.EqualTo(TestNow)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Update.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo("{\"Name\":{\"OldValue\":\"TestName\",\"NewValue\":\"Updated\"}}")); + } + + [Test] + public async Task ExistingRow_WhenSoftDeleted_SetsLastUpdatedToNow() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var entry = new TableWithLastUpdated + { + Name = "TestName" + }; + + testDBContext.TableWithLastUpdateds.Add(entry); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.TableWithLastUpdateds.Single(x => x.Name == entry.Name); + itemToEdit.Deleted = true; + + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + var editedItem = testDBContext.TableWithLastUpdateds.Single(x => x.Name == itemToEdit.Name); + + Assert.That(editedItem.LastUpdated, Is.EqualTo(TestNow)); + + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + Assert.That(auditDetail.DateTime, Is.EqualTo(TestNow)); + Assert.That(auditDetail.Id, Is.EqualTo(1)); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Delete.ToString())); + Assert.That(auditDetail.Fields, Is.EqualTo(string.Empty)); + } + + [Test] + public async Task ExistingChildRow_WhenSoftDeleted_SetsParentLastUpdatedToNow() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var entry = new TableWithLastUpdated + { + Name = "TestName" + }; + + testDBContext.TableWithLastUpdateds.Add(entry); + + var child = new ChildTableWithLastUpdated + { + ParentId = entry.Id, + Parent = entry, + Name = "Child row", + }; + + testDBContext.ChildTableWithLastUpdateds.Add(child); + + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.ChildTableWithLastUpdateds.Single(x => x.Name == child.Name); + itemToEdit.Deleted = true; + + await testDBContext.SaveChangesAsync(auditUserDetails); + + var editedItem = testDBContext.TableWithLastUpdateds.Single(x => x.Name == entry.Name); + + Assert.That(editedItem.LastUpdated, Is.EqualTo(TestNow)); + } + + [Test] + public async Task ExistingChildRow_WhenPurged_SetsParentLastUpdatedToNow() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var entry = new TableWithLastUpdated + { + Name = "TestName" + }; + + testDBContext.TableWithLastUpdateds.Add(entry); + + var child = new ChildTableWithLastUpdated + { + ParentId = entry.Id, + Parent = entry, + Name = "Child row", + }; + + testDBContext.ChildTableWithLastUpdateds.Add(child); + + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.ChildTableWithLastUpdateds.Single(x => x.Name == child.Name); + testDBContext.ChildTableWithLastUpdateds.Remove(itemToEdit); + + await testDBContext.SaveChangesAsync(auditUserDetails); + + var editedItem = testDBContext.TableWithLastUpdateds.Single(x => x.Name == entry.Name); + + Assert.That(editedItem.LastUpdated, Is.EqualTo(TestNow)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/SoftDeleteUnitTests.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/SoftDeleteUnitTests.cs new file mode 100644 index 0000000..4114103 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/AuditEngineCore/SoftDeleteUnitTests.cs @@ -0,0 +1,418 @@ +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.UnitTests.Helpers; +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.AuditEngineCore; + +[TestFixture] +public class SoftDeleteUnitTests : AuditEngineCoreTestBase +{ + [Test] + public async Task AddRow_ItemEditedHasNotDeleted_AuditEntryShowsAsUpdate() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 2000, + Name = "Leaf Level item", + Deleted = false + }; + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Name = "Altered Name"; + itemToEdit.Deleted = false; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Update.ToString())); + } + + [Test] + public async Task AddRow_ItemIsUndeleted_AuditEntryShowsAsRestore() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 2000, + Name = "Leaf Level item", + Deleted = true + }; + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Name = "Altered Name"; + itemToEdit.Deleted = false; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.Type, Is.EqualTo(AuditType.Restore.ToString())); + } + + [TestCase(true)] //Soft delete + [TestCase(false)] //Undelete + public async Task AddRow_TableHasSelfReferenceAndReferenceNull_AuditForSoftDeleteOrUndeleteRecorded(bool deleteRow) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = "Leaf Level item", + Deleted = !deleteRow + }; + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Deleted = deleteRow; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + + Assert.That(auditDetail.Type, Is.EqualTo(deleteRow ? AuditType.Delete.ToString() : AuditType.Restore.ToString())); + + Assert.That(auditDetail.Fields, Is.EqualTo( string.Empty)); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(1)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(0)); + } + + [TestCase(true)] //Soft delete + [TestCase(false)] //Undelete + public async Task AddRow_TableHasSingleParentItem_AuditForSoftDeleteOrUndeleteRecorded(bool deleteRow) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var rootTreeValue = new DeletableTreeValue + { + Id = 3000, + Name = "Root Level item", + Deleted = !deleteRow + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = "Leaf Level item", + Deleted = !deleteRow, + ParentId = rootTreeValue.Id + }; + + testDBContext.DeletableTreeValues.Add(rootTreeValue); + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Deleted = deleteRow; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + + Assert.That(auditDetail.Type, Is.EqualTo(deleteRow ? AuditType.Delete.ToString() : AuditType.Restore.ToString())); + + Assert.That(testDBContext.DeletableTreeValues.Count(), Is.EqualTo(2)); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(2)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var parentAuditEntry = auditEntries[1]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(2)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(rootTreeValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{rootTreeValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(1)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + } + + [TestCase(true)] //Soft delete + [TestCase(false)] //Undelete + public async Task AddRow_TableHasTwoParentLevels_AuditForSoftDeleteOrUndeleteRecorded(bool deleteRow) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var rootTreeValue = new DeletableTreeValue + { + Id = 300, + Name = "Root Level item", + Deleted = !deleteRow + }; + + var level1TreeValue = new DeletableTreeValue + { + Id = 3000, + Name = "Level 1 item", + Deleted = !deleteRow, + ParentId = rootTreeValue.Id + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = "Leaf Level item", + Deleted = !deleteRow, + ParentId = level1TreeValue.Id + }; + + testDBContext.DeletableTreeValues.Add(rootTreeValue); + testDBContext.DeletableTreeValues.Add(level1TreeValue); + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Deleted = deleteRow; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + + Assert.That(auditDetail.Type, Is.EqualTo(deleteRow ? AuditType.Delete.ToString() : AuditType.Restore.ToString())); + + Assert.That(testDBContext.DeletableTreeValues.Count(), Is.EqualTo(3)); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(3)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var level1AuditEntry = auditEntries[1]; + Assert.That(level1AuditEntry.Id, Is.EqualTo(2)); + Assert.That(level1AuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(level1AuditEntry.DisplayName, Is.EqualTo(level1TreeValue.Name)); + Assert.That(level1AuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(level1AuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{level1TreeValue.Id}}}")); + Assert.That(level1AuditEntry.IsPrimary, Is.False); + + var parentAuditEntry = auditEntries[2]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(3)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(rootTreeValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{rootTreeValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(2)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + + Assert.That(auditDrillHierarchies[1].ChildAuditDrillDownEntityId, Is.EqualTo(2)); + Assert.That(auditDrillHierarchies[1].ParentAuditDrillDownEntityId, Is.EqualTo(3)); + } + + [TestCase(true)] //Soft delete + [TestCase(false)] //Undelete + public async Task AddRow_TableHasThreeParentLevels_AuditForSoftDeleteOrUndeleteRecorded(bool deleteRow) + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "Test comment" + }; + + var rootTreeValue = new DeletableTreeValue + { + Id = 30, + Name = "Root Level item", + Deleted = !deleteRow + }; + + var level1TreeValue = new DeletableTreeValue + { + Id = 300, + Name = "Level 1 item", + Deleted = !deleteRow, + ParentId = rootTreeValue.Id + }; + + var level2TreeValue = new DeletableTreeValue + { + Id = 3000, + Name = "Level 2 item", + Deleted = !deleteRow, + ParentId = level1TreeValue.Id + }; + + var leafTreeValue = new DeletableTreeValue + { + Id = 30000, + Name = "Leaf Level item", + Deleted = !deleteRow, + ParentId = level2TreeValue.Id + }; + + testDBContext.DeletableTreeValues.Add(rootTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + testDBContext.DeletableTreeValues.Add(level1TreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + testDBContext.DeletableTreeValues.Add(level2TreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + testDBContext.DeletableTreeValues.Add(leafTreeValue); + await testDBContext.NoAuditSaveChangesAsync(); + + //Act + var itemToEdit = testDBContext.DeletableTreeValues.Single(x => x.Id == leafTreeValue.Id); + itemToEdit.Deleted = deleteRow; + await testDBContext.SaveChangesAsync(auditUserDetails); + + //Assert + Assert.That(testDBContext.AuditDetails.Count(), Is.EqualTo(1)); + var auditDetail = testDBContext.AuditDetails.First(); + Assert.That(auditDetail.UserDisplayName, Is.EqualTo(auditUserDetails.UserDisplayName)); + Assert.That(auditDetail.UserId, Is.EqualTo(auditUserDetails.UserId)); + Assert.That(auditDetail.Comment, Is.EqualTo(auditUserDetails.Comment)); + + Assert.That(auditDetail.Id, Is.EqualTo(1)); + + Assert.That(auditDetail.Type, Is.EqualTo(deleteRow ? AuditType.Delete.ToString() : AuditType.Restore.ToString())); + + Assert.That(testDBContext.DeletableTreeValues.Count(), Is.EqualTo(4)); + + Assert.That(testDBContext.AuditEntries.Count(), Is.EqualTo(4)); + + var auditEntries = testDBContext.AuditEntries.ToList(); + var childAuditEntry = auditEntries[0]; + Assert.That(childAuditEntry.Id, Is.EqualTo(1)); + Assert.That(childAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(childAuditEntry.DisplayName, Is.EqualTo(leafTreeValue.Name)); + Assert.That(childAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(childAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{leafTreeValue.Id}}}")); + Assert.That(childAuditEntry.IsPrimary, Is.True); + + var level1AuditEntry = auditEntries[1]; + Assert.That(level1AuditEntry.Id, Is.EqualTo(2)); + Assert.That(level1AuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(level1AuditEntry.DisplayName, Is.EqualTo(level2TreeValue.Name)); + Assert.That(level1AuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(level1AuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{level2TreeValue.Id}}}")); + Assert.That(level1AuditEntry.IsPrimary, Is.False); + + var level2AuditEntry = auditEntries[2]; + Assert.That(level2AuditEntry.Id, Is.EqualTo(3)); + Assert.That(level2AuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(level2AuditEntry.DisplayName, Is.EqualTo(level1TreeValue.Name)); + Assert.That(level2AuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(level2AuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{level1TreeValue.Id}}}")); + Assert.That(level2AuditEntry.IsPrimary, Is.False); + + var parentAuditEntry = auditEntries[3]; + Assert.That(parentAuditEntry.Id, Is.EqualTo(4)); + Assert.That(parentAuditEntry.EntityName, Is.EqualTo(typeof(DeletableTreeValue).FullName)); + Assert.That(parentAuditEntry.DisplayName, Is.EqualTo(rootTreeValue.Name)); + Assert.That(parentAuditEntry.AuditLogId, Is.EqualTo(auditDetail.Id)); + Assert.That(parentAuditEntry.PrimaryKey, Is.EqualTo($"{{\"Id\":{rootTreeValue.Id}}}")); + Assert.That(parentAuditEntry.IsPrimary, Is.False); + + Assert.That(testDBContext.AuditDrillHierarchies.Count(), Is.EqualTo(3)); + var auditDrillHierarchies = testDBContext.AuditDrillHierarchies.ToList(); + Assert.That(auditDrillHierarchies[0].ChildAuditDrillDownEntityId, Is.EqualTo(1)); + Assert.That(auditDrillHierarchies[0].ParentAuditDrillDownEntityId, Is.EqualTo(2)); + + Assert.That(auditDrillHierarchies[1].ChildAuditDrillDownEntityId, Is.EqualTo(2)); + Assert.That(auditDrillHierarchies[1].ParentAuditDrillDownEntityId, Is.EqualTo(3)); + + Assert.That(auditDrillHierarchies[2].ChildAuditDrillDownEntityId, Is.EqualTo(3)); + Assert.That(auditDrillHierarchies[2].ParentAuditDrillDownEntityId, Is.EqualTo(4)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/GlobalSuppressions.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/AuditEngineCoreTestBase.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/AuditEngineCoreTestBase.cs new file mode 100644 index 0000000..f6f3132 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/AuditEngineCoreTestBase.cs @@ -0,0 +1,26 @@ +using eSuite.Core.Clock; +using Moq; +using NUnit.Framework; + +namespace e_suite.Database.Audit.UnitTests.Helpers; + +public class AuditEngineCoreTestBase +{ + protected TestDbContextFactory testDbContextFactory = null!; + protected Mock _clockMock = null!; + public DateTimeOffset TestNow = DateTimeOffset.Now; + + protected TestDbContext testDBContext = null!; + + [SetUp] + public void Setup() + { + testDbContextFactory = new TestDbContextFactory(); + + _clockMock = new Mock(); + _clockMock.Setup(x => x.GetNow).Returns(() => TestNow); + + + testDBContext = testDbContextFactory.CreateContext(_clockMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ChildTableWithLastUpdated.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ChildTableWithLastUpdated.cs new file mode 100644 index 0000000..e2bb667 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ChildTableWithLastUpdated.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +public class ChildTableWithLastUpdated : IId +{ + [Key] + public long Id { get; set; } + + public string Name { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + public bool Deleted { get; set; } = false; + + public long? ParentId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(ParentId))] + public TableWithLastUpdated Parent { get; set; } = null!; + + +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ChildValue.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ChildValue.cs new file mode 100644 index 0000000..a485d28 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ChildValue.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("ChildValues", Schema = "ParentChild")] +public class ChildValue : IId +{ + [Key] + public long Id { get; set; } + + public long? ParentId { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = string.Empty; + + [AuditParent] + [ForeignKey(nameof(ParentId))] + public ParentValue ParentValue { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/DeletableTreeValue.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/DeletableTreeValue.cs new file mode 100644 index 0000000..fcde738 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/DeletableTreeValue.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("DeletableTreeValues", Schema = "DeletableTree")] +public class DeletableTreeValue : IId +{ + [Key] + public long Id { get; set; } + + [AuditSoftDelete(true)] + [Required] + public bool Deleted { get; set; } = false; + + public long? ParentId { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = null!; + + [Required, MaxLength(50)] + public string Test { get; set; } = string.Empty; + + [AuditParent] + [ForeignKey(nameof(ParentId))] + public DeletableTreeValue Parent { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/EntryWithName.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/EntryWithName.cs new file mode 100644 index 0000000..36a9497 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/EntryWithName.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("EntriesWithName", Schema = "StandAlone")] +public class EntryWithName : IId +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/GeneralComment.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/GeneralComment.cs new file mode 100644 index 0000000..1488b0b --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/GeneralComment.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[NoAudit] +[Table("GeneralComments", Schema = "NotAudited")] +public class GeneralComment : IId +{ + [Key] + public long Id { get; set; } + + [Required, MaxLength(100)] + public string Comment { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/GrandParentValue.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/GrandParentValue.cs new file mode 100644 index 0000000..001d496 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/GrandParentValue.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("GrandParentValues", Schema = "ParentChild")] +public class GrandParentValue : IId +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/LinkedEntryWithName.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/LinkedEntryWithName.cs new file mode 100644 index 0000000..d0b4822 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/LinkedEntryWithName.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("LinkedEntriesWithName", Schema = "HasALink")] +public class LinkedEntryWithName : IId +{ + [Key] + public long Id { get; set; } + + [Required] public long LinkId { get; set; } + + [AuditName] + [NotMapped] + public string Name => $"{GrandParentValue.Name} testing"; + + public string SomethingToChange { get; set; } = string.Empty; + + [ForeignKey(nameof(LinkId))] + public GrandParentValue GrandParentValue { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ParentValue.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ParentValue.cs new file mode 100644 index 0000000..c6cd955 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/ParentValue.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("ParentValues", Schema = "ParentChild")] +public class ParentValue : IId +{ + [Key] + public long Id { get; set; } + + public long? GrandParentId { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = null!; + + [AuditParent] + [ForeignKey(nameof(GrandParentId))] + public GrandParentValue GrandParentValue { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/RecordedComment.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/RecordedComment.cs new file mode 100644 index 0000000..2d3bbdc --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/RecordedComment.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("RecordedComments", Schema = "IsAudited")] +public class RecordedComment : IId +{ + + [Key] + public long Id { get; set; } + + [Required, MaxLength(100)] + public string Comment { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/SecretValue.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/SecretValue.cs new file mode 100644 index 0000000..60d7e9b --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/SecretValue.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("SecretValues", Schema = "StandAlone")] +public class SecretValue : IId +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = null!; + + [RedactAudit] + public string Secret { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/SimpleTreeValue.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/SimpleTreeValue.cs new file mode 100644 index 0000000..d92e69d --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/SimpleTreeValue.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +[Table("SimpleTreeValues", Schema = "SimpleTree")] +public class SimpleTreeValue : IId +{ + [Key] + public long Id { get; set; } + + public long? ParentId { get; set; } + + [AuditName] + [Required, MaxLength(50)] + public string Name { get; set; } = null!; + + [AuditParent] + [ForeignKey(nameof(ParentId))] + public SimpleTreeValue Parent { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithDisplayEnums.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithDisplayEnums.cs new file mode 100644 index 0000000..1aeccfe --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithDisplayEnums.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +public enum DisplayTestEnum +{ + [Display(Name = "Item 1")] + Item1, + [Display(Name = "Item 2")] + Item2 +} + +[Table("TableWithDisplayEnums", Schema = "ENums")] +public class TableWithDisplayEnums : IId +{ + [Key] + public long Id { get; set; } + + public DisplayTestEnum DisplayEnum { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithEnums.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithEnums.cs new file mode 100644 index 0000000..7a0c692 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithEnums.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +public enum TestEnum +{ + Item1, + Item2 +} + +[Table("TableWithEnums", Schema = "ENums")] +public class TableWithEnums : IId +{ + [Key] + public long Id { get; set; } + + public TestEnum RawEnum { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithLastUpdated.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithLastUpdated.cs new file mode 100644 index 0000000..a684318 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/Tables/TableWithLastUpdated.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.UnitTests.Helpers.Tables; + +public class TableWithLastUpdated : IId +{ + [Key] + public long Id { get; set; } + + public string Name { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + public bool Deleted { get; set; } = false; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/TestDbContext.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/TestDbContext.cs new file mode 100644 index 0000000..255f1df --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/TestDbContext.cs @@ -0,0 +1,34 @@ +using e_suite.Database.Audit.UnitTests.Helpers.Tables; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Audit.UnitTests.Helpers; + +public class TestDbContext : AuditableEntityContext +{ + public TestDbContext(DbContextOptions options, IClock clock) : base(options, clock) + { + } + + public DbSet GeneralComments { get; set; } = null!; + public DbSet RecordedComments { get; set; } = null!; + public DbSet EntriesWithName { get; set; } = null!; + public DbSet LinkedEntryWithName { get; set; } = null!; + public DbSet SecretValues { get; set; } = null!; + + public DbSet GrandParentValues { get; set; } = null!; + public DbSet ParentValues { get; set; } = null!; + public DbSet ChildValues { get; set; } = null!; + + public DbSet SimpleTreeValues { get; set; } = null!; + + public DbSet DeletableTreeValues { get; set; } = null!; + + public DbSet TableWithEnums { get; set; } = null!; + + public DbSet TableWithDisplayEnums { get; set; } = null!; + + public DbSet TableWithLastUpdateds { get; set; } = null!; + + public DbSet ChildTableWithLastUpdateds { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/TestDbContextFactory.cs b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/TestDbContextFactory.cs new file mode 100644 index 0000000..6c4dcec --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/Helpers/TestDbContextFactory.cs @@ -0,0 +1,45 @@ +using System.Data.Common; +using eSuite.Core.Clock; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Audit.UnitTests.Helpers; + +public class TestDbContextFactory : IDisposable +{ + //private const string _connectionString = "Data Source = InMemorySample; Mode=Memory;Cache=Shared"; + private const string _connectionString = "DataSource=:memory:"; + + private DbConnection _connection = null!; + + private DbContextOptions CreateOptions() + { + return new DbContextOptionsBuilder() + .UseSqlite(_connection).Options; + } + + public TestDbContext CreateContext( IClock clock) + { + if (_connection == null) + { + _connection = new SqliteConnection(_connectionString); + _connection.Open(); + + var options = CreateOptions(); + using var context = new TestDbContext(options, clock); + context.Database.EnsureCreated(); + } + + return new TestDbContext(CreateOptions(), clock); + } + + public void Dispose() + { + if (_connection != null) + { + _connection.Dispose(); + _connection = null!; + } + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/e-suite.Database.Audit.UnitTests.csproj b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/e-suite.Database.Audit.UnitTests.csproj new file mode 100644 index 0000000..0fbfadf --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.UnitTests/e-suite.Database.Audit.UnitTests.csproj @@ -0,0 +1,30 @@ + + + + net10.0 + e_suite.Database.Audit.UnitTests + enable + enable + + + + 1701;1702;NETSDK1206 + + + + 1701;1702;NETSDK1206 + + + + + + + + + + + + + + + diff --git a/e-suite.Database.Audit/e-suite.Database.Audit.sln b/e-suite.Database.Audit/e-suite.Database.Audit.sln new file mode 100644 index 0000000..307a1b8 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.Audit", "e-suite.Database.Audit\e-suite.Database.Audit.csproj", "{9EF9AB17-A799-484F-987C-19A2F7014FB0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{CFFC0559-8CEE-4CA3-B216-328A1BC2B7DC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{B7242D22-975E-4DA1-8F22-4AF3A911465F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Database.Audit.UnitTests", "e-suite.Database.Audit.UnitTests\e-suite.Database.Audit.UnitTests.csproj", "{57215FA5-39D9-40F3-AE9B-F492092C4C82}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9EF9AB17-A799-484F-987C-19A2F7014FB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EF9AB17-A799-484F-987C-19A2F7014FB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EF9AB17-A799-484F-987C-19A2F7014FB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EF9AB17-A799-484F-987C-19A2F7014FB0}.Release|Any CPU.Build.0 = Release|Any CPU + {57215FA5-39D9-40F3-AE9B-F492092C4C82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57215FA5-39D9-40F3-AE9B-F492092C4C82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57215FA5-39D9-40F3-AE9B-F492092C4C82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {57215FA5-39D9-40F3-AE9B-F492092C4C82}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B7242D22-975E-4DA1-8F22-4AF3A911465F} = {CFFC0559-8CEE-4CA3-B216-328A1BC2B7DC} + {57215FA5-39D9-40F3-AE9B-F492092C4C82} = {B7242D22-975E-4DA1-8F22-4AF3A911465F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B625E122-1B0A-4754-9EEE-B2DAC1C06E59} + EndGlobalSection +EndGlobal diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditLastUpdatedAttribute.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditLastUpdatedAttribute.cs new file mode 100644 index 0000000..f327875 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditLastUpdatedAttribute.cs @@ -0,0 +1,7 @@ +namespace e_suite.Database.Audit.Attributes; + +//Used by Auto audit trail to apply the current UTC date and time +[AttributeUsage(AttributeTargets.Property)] +public class AuditLastUpdatedAttribute : Attribute +{ +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditNameAttribute.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditNameAttribute.cs new file mode 100644 index 0000000..1da2724 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditNameAttribute.cs @@ -0,0 +1,9 @@ +namespace e_suite.Database.Audit.Attributes; + +/// +/// Used by the auto audit trail to know that the property this is attached to is a displayname +/// +[AttributeUsage(AttributeTargets.Property)] +public class AuditNameAttribute : Attribute +{ +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditParentAttribute.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditParentAttribute.cs new file mode 100644 index 0000000..fc3ca54 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditParentAttribute.cs @@ -0,0 +1,9 @@ +namespace e_suite.Database.Audit.Attributes; + +/// +/// Used by the Auto Audit trail to denote this property being a link to a parent +/// +[AttributeUsage(AttributeTargets.Property)] +public class AuditParentAttribute : Attribute +{ +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditSoftDeleteAttribute.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditSoftDeleteAttribute.cs new file mode 100644 index 0000000..edba441 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/AuditSoftDeleteAttribute.cs @@ -0,0 +1,15 @@ +namespace e_suite.Database.Audit.Attributes; + +/// +/// Used by the Auto Audit trail to mark this record as a soft delete flag. Please also provide the value for deleted +/// +[AttributeUsage(AttributeTargets.Property)] +public class AuditSoftDeleteAttribute : Attribute +{ + public AuditSoftDeleteAttribute(object deletedValue) + { + DeletedValue = deletedValue; + } + + public object DeletedValue { get; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/NoAuditAttribute.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/NoAuditAttribute.cs new file mode 100644 index 0000000..4bc69e1 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/NoAuditAttribute.cs @@ -0,0 +1,6 @@ +namespace e_suite.Database.Audit.Attributes; + +[AttributeUsage(AttributeTargets.Class)] +public class NoAuditAttribute : Attribute +{ +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/RedactAuditAttribute.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/RedactAuditAttribute.cs new file mode 100644 index 0000000..2783fcb --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Attributes/RedactAuditAttribute.cs @@ -0,0 +1,9 @@ +namespace e_suite.Database.Audit.Attributes; + +/// +/// Used by the Auto Audit trail to know that the content of this field should be redacted in the Audit logs. +/// +[AttributeUsage(AttributeTargets.Property)] +public class RedactAuditAttribute : Attribute +{ +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditDrillUp.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditDrillUp.cs new file mode 100644 index 0000000..f4c521d --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditDrillUp.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; + +namespace e_suite.Database.Audit.AuditEngine; + +public class AuditDrillUp +{ + public string EntityName { get; set; } = null!; + public Dictionary PrimaryKey { get; } = new(); + public string? EntryName { get; set; } + + public List Parents { get; set; } = new(); + + public string ToPrimaryKeyJson() + { + return JsonConvert.SerializeObject(PrimaryKey, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditEngineCore.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditEngineCore.cs new file mode 100644 index 0000000..bcc796f --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditEngineCore.cs @@ -0,0 +1,502 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; +using System.Reflection; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Extensions; +using e_suite.Database.Audit.Tables.Audit; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace e_suite.Database.Audit.AuditEngine; + +public class AuditEngineCore +{ + private readonly AuditableEntityContext _auditableEntityContext; + private readonly IClock _clock; + + public AuditEngineCore(AuditableEntityContext auditableEntityContext, IClock clock) + { + _auditableEntityContext = auditableEntityContext; + _clock = clock; + } + +#pragma warning disable IDE0060 // Remove unused parameter + public List OnBeforeSaveChanges(AuditableEntityContext dbContext, AuditUserDetails auditUserDetails, CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + if (!_auditableEntityContext.ChangeTracker.AutoDetectChangesEnabled) + { + _auditableEntityContext.ChangeTracker.DetectChanges(); + } + + var auditEntries = new List(); + foreach (var entry in _auditableEntityContext.ChangeTracker.Entries()) + { + cancellationToken.ThrowIfCancellationRequested(); + if (HasNoAuditAttribute(entry.Entity) || entry.State == EntityState.Detached + || entry.State == EntityState.Unchanged) + continue; + + var auditEntry = new AuditRecorder(entry, auditUserDetails, _clock); + + auditEntry.AuditType = entry.State switch + { + EntityState.Added => AuditType.Create, + EntityState.Deleted => AuditType.Purge, + EntityState.Modified => AuditType.Update, + _ => auditEntry.AuditType + }; + + foreach (var property in entry.Properties) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (property.IsTemporary) + { + continue; + } + + var propertyName = property.Metadata.Name; + + var propertyInfo = entry.Entity.GetType().GetProperties().Single(x => x.Name == propertyName); + + var isLastUpdated = propertyInfo.CustomAttributes.Any(x => x.AttributeType == typeof(AuditLastUpdatedAttribute)); + if (isLastUpdated) + { + continue; + } + + var currentValue = property.CurrentValue == null ? null : Convert.ChangeType(property.CurrentValue, property.CurrentValue!.GetType()); + var oldValue = property.OriginalValue == null ? null : Convert.ChangeType(property.OriginalValue, property.OriginalValue!.GetType()); + + var isSoftDelete = + propertyInfo.CustomAttributes.SingleOrDefault(x => + x.AttributeType == typeof(AuditSoftDeleteAttribute)); + if (isSoftDelete != null && auditEntry.AuditType == AuditType.Update) + { + if (property.IsModified) + { + if (!currentValue!.Equals(oldValue)) + { + var deletedValue = isSoftDelete.ConstructorArguments[0]; + auditEntry.AuditType = deletedValue.Value!.Equals(currentValue) + ? AuditType.Delete + : AuditType.Restore; + continue; + } + } + } + + var isRedacted = + propertyInfo.CustomAttributes.Any(x => x.AttributeType == typeof(RedactAuditAttribute)); + + var currentDisplayName = GetNewName(property) ?? GetEnumAsString(currentValue); + var oldDisplayName = GetOldName(property) ?? GetEnumAsString(oldValue); + + var valuesMatch = (currentValue == null && oldValue == null) || + (currentValue != null && currentValue.Equals(oldValue)); + + if (isRedacted) + { + const string redacted = ""; + + currentValue = redacted; + oldValue = redacted; + + currentDisplayName = null; + oldDisplayName = null; + } + + switch (entry.State) + { + case EntityState.Added: + auditEntry.Fields[propertyName] = new Change + { + NewValue = currentValue, + NewDisplayName = currentDisplayName + }; + break; + case EntityState.Deleted: + auditEntry.Fields[propertyName] = new Change + { + OldValue = oldValue, + OldDisplayName = oldDisplayName + }; + break; + case EntityState.Modified: + if (!valuesMatch) + { + auditEntry.Fields[propertyName] = new Change + { + OldValue = oldValue, + OldDisplayName = oldDisplayName, + NewValue = currentValue, + NewDisplayName = currentDisplayName + }; + } + + break; + } + } + + if (auditEntry.Fields.Count != 0 | auditEntry.AuditType != AuditType.Update ) + auditEntries.Add(auditEntry); + } + + return auditEntries; + } + + public void OnAfterSaveChanges(AuditableEntityContext dbContext, List auditEntries, CancellationToken cancellationToken) + { + foreach (var auditEntry in auditEntries) + { + cancellationToken.ThrowIfCancellationRequested(); + if (auditEntry.Entry != null) + auditEntry.DrillUp = TraceDrillUp(dbContext, auditEntry.Entry.Entity, cancellationToken); + + AddAuditEntry(auditEntry, cancellationToken); + } + } + + private void AddAuditEntry(AuditRecorder auditEntry, CancellationToken cancellationToken) + { + var auditLog = _auditableEntityContext.AuditDetails.Add(auditEntry.ToAudit()); + cancellationToken.ThrowIfCancellationRequested(); + var childAuditDrillUp = auditEntry.DrillUp; + + var childDrillDownEntity = new AuditEntry + { + AuditLog = auditLog.Entity, + DisplayName = childAuditDrillUp.EntryName, + EntityName = childAuditDrillUp.EntityName, + PrimaryKey = childAuditDrillUp.ToPrimaryKeyJson(), + }; + _auditableEntityContext.AuditEntries.Add(childDrillDownEntity); + + childDrillDownEntity.IsPrimary = true; + + foreach (var parent in childAuditDrillUp.Parents) + { + cancellationToken.ThrowIfCancellationRequested(); + AddParent(auditLog.Entity, childDrillDownEntity, parent, cancellationToken); + } + } + + private void AddParent(AuditDetail auditLog, AuditEntry childDrillDownEntity, AuditDrillUp parent, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + var parentDrillDownEntity = new AuditEntry + { + AuditLog = auditLog, + DisplayName = parent.EntryName, + EntityName = parent.EntityName, + PrimaryKey = parent.ToPrimaryKeyJson(), + }; + _auditableEntityContext.AuditEntries.Add(childDrillDownEntity); + + _auditableEntityContext.AuditDrillHierarchies.Add(new AuditDrillHierarchy + { + ParentAuditDrillDownEntity = parentDrillDownEntity, + ChildAuditDrillDownEntity = childDrillDownEntity + }); + + foreach (var grandparent in parent.Parents) + AddParent(auditLog, parentDrillDownEntity, grandparent, cancellationToken); + } + + private AuditDrillUp TraceDrillUp(AuditableEntityContext dbContext, object entity, CancellationToken cancellationToken) + { + var type = entity.GetType(); + var drillUp = new AuditDrillUp + { + EntityName = type.FullName ?? type.Name, + }; + + try + { + drillUp.EntryName = GetAuditName(entity) ?? string.Empty; + } + catch + { + LoadForeignKeysIfNotAlreadyLoaded(dbContext, entity, cancellationToken); + drillUp.EntryName = GetAuditName(entity) ?? string.Empty; + } + + var properties = type.GetProperties(); + foreach (var property in properties) + { + cancellationToken.ThrowIfCancellationRequested(); + var isPrimaryKey = property.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(KeyAttribute)) != null; + if (isPrimaryKey) + { + drillUp.PrimaryKey[property.Name] = property.GetValue(entity); + } + + var isLastUpdated = property.CustomAttributes.Any(x => x.AttributeType == typeof(AuditLastUpdatedAttribute)); + if (isLastUpdated) + { + property.SetValue(entity, _clock.GetNow); + } + + var isParent = property.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(AuditParentAttribute)) != null; + if (isParent) + { + LoadParentIfNotAlreadyLoaded(dbContext, property, entity, cancellationToken); + + var parent = property.GetValue(entity); + if (parent != null) + { + var parentDrillUp = TraceDrillUp(dbContext, parent, cancellationToken); + drillUp.Parents.Add(parentDrillUp); + } + } + } + + return drillUp; + } + + private static void LoadForeignKeysIfNotAlreadyLoaded(AuditableEntityContext dbContext, object entity, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + var type = entity.GetType(); + var properties = type.GetProperties(); + + foreach (var property in properties) + { + var foreignKeyAttribute = property.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(ForeignKeyAttribute)); + var lookupFieldName = foreignKeyAttribute?.ConstructorArguments[0].Value?.ToString(); + if (lookupFieldName == null) + continue; + + var lookupField = type.GetProperty(lookupFieldName); + var lookupValue = lookupField?.GetValue(entity); + if (lookupValue == null) + continue; + + cancellationToken.ThrowIfCancellationRequested(); + var dbSetProperty = FindDbSet(dbContext, property.PropertyType); + if (dbSetProperty == null) + continue; + + cancellationToken.ThrowIfCancellationRequested(); + if (dbSetProperty.GetValue(dbContext) is not IQueryable dbSet) + continue; + + + cancellationToken.ThrowIfCancellationRequested(); + var primaryKeyProperty = GetPrimaryKeyProperty(dbSet.ElementType); + if (primaryKeyProperty == null) + continue; + + cancellationToken.ThrowIfCancellationRequested(); + var result = FindObjectByProperty(dbSet, primaryKeyProperty, lookupValue); + + cancellationToken.ThrowIfCancellationRequested(); + property.SetValue(entity, result); + } + } + + private static void LoadParentIfNotAlreadyLoaded(AuditableEntityContext dbContext, PropertyInfo property, object entity, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + var parent = property.GetValue(entity); + if (parent != null) + return; + + cancellationToken.ThrowIfCancellationRequested(); + var foreignKeyAttribute = property.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(ForeignKeyAttribute)); + var lookupFieldName = foreignKeyAttribute?.ConstructorArguments[0].Value?.ToString(); + if (lookupFieldName == null) + return; + + cancellationToken.ThrowIfCancellationRequested(); + var entityType = entity.GetType(); + var lookupField = entityType.GetProperty(lookupFieldName); + var lookupValue = lookupField?.GetValue(entity); + if (lookupValue == null) + return; + + cancellationToken.ThrowIfCancellationRequested(); + var dbSetProperty = FindDbSet(dbContext, property.PropertyType); + if (dbSetProperty == null) + return; + + cancellationToken.ThrowIfCancellationRequested(); + if (dbSetProperty.GetValue(dbContext) is not IQueryable dbSet) + return; + + + cancellationToken.ThrowIfCancellationRequested(); + var primaryKeyProperty = GetPrimaryKeyProperty(dbSet.ElementType); + if (primaryKeyProperty == null) + return; + + cancellationToken.ThrowIfCancellationRequested(); + var result = FindObjectByProperty(dbSet, primaryKeyProperty, lookupValue); + + cancellationToken.ThrowIfCancellationRequested(); + property.SetValue(entity, result); + } + + private static object FindObjectByProperty(IQueryable query, PropertyInfo primaryKeyProperty, object lookupValue) + { + var parameter = Expression.Parameter(query.ElementType); + var propExpr = Expression.Property(parameter, primaryKeyProperty); + var lambdaBody = Expression.Equal(propExpr, Expression.Constant(lookupValue, primaryKeyProperty.PropertyType)); + var filterEFn = Expression.Lambda(lambdaBody, parameter); + return query.Where(filterEFn).FirstOrDefault(); + } + + private static PropertyInfo? GetPrimaryKeyProperty(Type entityType) + { + var entityProperties = entityType.GetProperties(); + + foreach (var entityProperty in entityProperties) + { + if (entityProperty.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(KeyAttribute)) != null) + { + return entityProperty; + } + } + + return null; + } + + private static PropertyInfo? FindDbSet(AuditableEntityContext dbContext, Type type) + { + var thisProperties = dbContext.GetType().GetProperties(); + foreach (var propertyInfo in thisProperties) + { + if (!propertyInfo.PropertyType.IsGenericType) + continue; + + if (propertyInfo.PropertyType.GetGenericTypeDefinition() != typeof(DbSet<>)) + continue; + + if (propertyInfo.PropertyType.GenericTypeArguments[0] == type) + return propertyInfo; + } + + return null; + } + + private static string? GetEnumAsString(object? enumValue) + { + if (enumValue == null || !enumValue.GetType().IsEnum) + return null; + + var displayAttribute = ((Enum)enumValue).GetAttribute(); + return displayAttribute != null ? displayAttribute.Name : enumValue.ToString(); + } + + private static string? GetNewName(PropertyEntry property) + { + var foreignKeyPropertyName = GetForeignKeyPropertyName(property); + if (foreignKeyPropertyName == null) + return null; + + var foreignKeyPropertyType = GetForeignKeyPropertyType(property, foreignKeyPropertyName); + + if (foreignKeyPropertyType == null) + return null; + + var value = property.EntityEntry.Entity.GetType().GetProperty(foreignKeyPropertyType.Name) + ?.GetValue(property.EntityEntry.Entity, null); + + return GetAuditName(value); + } + + private static string? GetAuditName(object? value) + { + if (value == null) + return null; + + var properties = value.GetType().GetProperties(); + foreach (var propertyInfo in properties) + { + var auditNameProperty = + propertyInfo.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(AuditNameAttribute)); + if (auditNameProperty == null) + continue; + + var actualValue = propertyInfo.GetValue(value, null); + { + return actualValue?.ToString(); + } + } + + return null; + } + + private string? GetOldName(PropertyEntry property) + { + if (property.OriginalValue == null) + return null; + + var foreignKeyPropertyName = GetForeignKeyPropertyName(property); + if (foreignKeyPropertyName == null) + return null; + + var foreignKeyPropertyType = GetForeignKeyPropertyType(property, foreignKeyPropertyName); + + if (foreignKeyPropertyType == null) + return null; + + var dbSetProperty = FindDbSet(_auditableEntityContext, foreignKeyPropertyType.PropertyType)!; + var dbSet = (dbSetProperty.GetValue(_auditableEntityContext) as IQueryable)!; + var primaryKeyProperty = GetPrimaryKeyProperty(dbSet.ElementType)!; + var value = FindObjectByProperty(dbSet, primaryKeyProperty, property.OriginalValue!); + + return GetAuditName(value); + } + + private static PropertyInfo? GetForeignKeyPropertyType(PropertyEntry property, string foreignKeyPropertyName) + { + var entityProperties = property.EntityEntry.Entity.GetType().GetProperties(); + foreach (var entityProperty in entityProperties) + { + if (entityProperty.Name == foreignKeyPropertyName) + { + return entityProperty; + } + } + + return null; + } + + private static string? GetForeignKeyPropertyName(PropertyEntry property) + { + var propertyInfo = property.EntityEntry.Entity.GetType().GetProperties(); + foreach (var entityProperty in propertyInfo) + { + var foreignKeyAttributeData = entityProperty.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(ForeignKeyAttribute)); + if (foreignKeyAttributeData != null) + { + if (foreignKeyAttributeData.ConstructorArguments.Any(x => x.Value!.Equals(property.Metadata.Name))) + { + return entityProperty.Name; + } + } + } + + return null; + } + + private static bool HasNoAuditAttribute(object entity) + { + var type = entity.GetType(); + + foreach (var attribute in type.CustomAttributes) + { + if (attribute.AttributeType == typeof(NoAuditAttribute)) + { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditRecorder.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditRecorder.cs new file mode 100644 index 0000000..163f719 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditRecorder.cs @@ -0,0 +1,44 @@ +using e_suite.Database.Audit.Tables.Audit; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Newtonsoft.Json; + +namespace e_suite.Database.Audit.AuditEngine; + +public class AuditRecorder +{ + private readonly IClock _clock; + + public AuditRecorder(EntityEntry? entry, AuditUserDetails auditUserDetails, IClock clock) + { + _clock = clock; + Entry = entry; + UserId = auditUserDetails.UserId; + UserDisplayName = auditUserDetails.UserDisplayName; + Comment = auditUserDetails.Comment; + } + public EntityEntry? Entry { get; } + public long UserId { get; set; } + public string UserDisplayName { get; set; } + public Dictionary Fields { get; } = []; + public AuditDrillUp DrillUp { get; set; } = null!; + public AuditType AuditType { get; set; } + public string Comment { get; set; } + + public AuditDetail ToAudit() + { + var audit = new AuditDetail + { + UserId = UserId, + UserDisplayName = UserDisplayName, + Type = AuditType.ToString(), + Comment = Comment, + DateTime = _clock.GetNow, + Fields = Fields.Count == 0 ? string.Empty : JsonConvert.SerializeObject(Fields, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }) + }; + return audit; + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditType.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditType.cs new file mode 100644 index 0000000..7cc81dc --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/AuditType.cs @@ -0,0 +1,11 @@ +namespace e_suite.Database.Audit.AuditEngine; + +public enum AuditType +{ + Create, + Update, + Purge, //A Hard delete + Delete, //A Soft delete + Restore, //An Undelete + EmailSent +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/Change.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/Change.cs new file mode 100644 index 0000000..44b956f --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditEngine/Change.cs @@ -0,0 +1,9 @@ +namespace e_suite.Database.Audit.AuditEngine; + +public class Change +{ + public object? OldValue { get; set; } + public string? OldDisplayName { get; set; } + public object? NewValue { get; set; } + public string? NewDisplayName { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditUserDetails.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditUserDetails.cs new file mode 100644 index 0000000..e5079fd --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditUserDetails.cs @@ -0,0 +1,8 @@ +namespace e_suite.Database.Audit; + +public class AuditUserDetails +{ + public long UserId { get; set; } + public string UserDisplayName { get; set; } = string.Empty; + public string Comment { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/AuditableEntityContext.cs b/e-suite.Database.Audit/e-suite.Database.Audit/AuditableEntityContext.cs new file mode 100644 index 0000000..7ed7ddc --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/AuditableEntityContext.cs @@ -0,0 +1,75 @@ +using System.Runtime.CompilerServices; +using System.Threading; +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Audit.Extensions; +using e_suite.Database.Audit.Tables.Audit; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Audit; + +public abstract class AuditableEntityContext : DbContext, IAudit +{ + private readonly AuditEngineCore _auditEngine; + private readonly IClock _clock; + + protected AuditableEntityContext(DbContextOptions options, IClock clock) : base(options) + { + _clock = clock; + _auditEngine = new AuditEngineCore(this, clock); + } + + public DbSet AuditDetails { get; set; } = null!; + + public DbSet AuditEntries { get; set; } = null!; + + public DbSet AuditDrillHierarchies { get; set; } = null!; + + public virtual async Task NoAuditSaveChangesAsync() + { + return await NoAuditSaveChangesAsync(default!); + } + + public virtual async Task NoAuditSaveChangesAsync(CancellationToken cancellationToken) + { + return await SaveChangesAsync(cancellationToken); + } + + public virtual async Task SaveChangesAsync(AuditUserDetails auditUserDetails) + { + return await SaveChangesAsync(auditUserDetails, default); + } + + private new async Task SaveChangesAsync(CancellationToken cancellationToken) + { + return await base.SaveChangesAsync(cancellationToken); + } + + public virtual async Task SaveChangesAsync(AuditUserDetails auditUserDetails, CancellationToken cancellationToken) + { + var auditEntries = _auditEngine.OnBeforeSaveChanges(this, auditUserDetails, cancellationToken); + cancellationToken.ThrowIfCancellationRequested(); + var result = await base.SaveChangesAsync(cancellationToken); + cancellationToken.ThrowIfCancellationRequested(); + _auditEngine.OnAfterSaveChanges(this, auditEntries, cancellationToken); + cancellationToken.ThrowIfCancellationRequested(); + await base.SaveChangesAsync(cancellationToken); + return result; + } + + public virtual async Task AddAdhocAuditEntry(AuditUserDetails auditUserDetails, AuditType auditType, Dictionary fields, CancellationToken cancellationToken) + { + var auditEntries = new List(); + + var auditEntry = new AuditRecorder(null, auditUserDetails, _clock) + { + AuditType = auditType + }; + auditEntry.Fields.AddRange(fields); + + auditEntries.Add(auditEntry); + + _auditEngine.OnAfterSaveChanges(this, auditEntries, cancellationToken); + return await base.SaveChangesAsync(cancellationToken); + } +} diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Extensions/DictionaryExtensions.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Extensions/DictionaryExtensions.cs new file mode 100644 index 0000000..18a557b --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Extensions/DictionaryExtensions.cs @@ -0,0 +1,23 @@ +using System.Data; + +namespace e_suite.Database.Audit.Extensions; + +public static class DictionaryExtensions +{ + public static void AddRange(this Dictionary source, Dictionary collection) where TKey : notnull + { + ArgumentNullException.ThrowIfNull(collection, nameof(collection)); + + foreach (var item in collection) + { + if (!source.ContainsKey(item.Key)) + { + source.Add(item.Key, item.Value); + } + else + { + throw new DuplicateNameException("duplicate entries found whilst combining dictionaries"); + } + } + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Extensions/ENumExtensions.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Extensions/ENumExtensions.cs new file mode 100644 index 0000000..84dd030 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Extensions/ENumExtensions.cs @@ -0,0 +1,19 @@ +using System.Reflection; + +namespace e_suite.Database.Audit.Extensions; + +public static class ENumExtensions +{ + /// + /// A generic extension method that aids in reflecting + /// and retrieving any attribute that is applied to an `Enum`. + /// + public static TAttribute? GetAttribute(this Enum enumValue) + where TAttribute : Attribute + { + return enumValue.GetType() + .GetMember(enumValue.ToString()) + .First() + .GetCustomAttribute(); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/GlobalSuppressions.cs b/e-suite.Database.Audit/e-suite.Database.Audit/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/IDatabaseAudit.cs b/e-suite.Database.Audit/e-suite.Database.Audit/IDatabaseAudit.cs new file mode 100644 index 0000000..2b71159 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/IDatabaseAudit.cs @@ -0,0 +1,12 @@ +namespace e_suite.Database.Audit; + +public interface IDatabaseAudit +{ + Task SaveChangesAsync(AuditUserDetails auditUserDetails); + + Task SaveChangesAsync(AuditUserDetails auditUserDetails, CancellationToken cancellationToken); + + Task NoAuditSaveChangesAsync(); + + Task NoAuditSaveChangesAsync(CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Models/IId.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Models/IId.cs new file mode 100644 index 0000000..c474b33 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Models/IId.cs @@ -0,0 +1,6 @@ +namespace e_suite.Database.Audit.Models; + +public interface IId +{ + public long Id { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditDetail.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditDetail.cs new file mode 100644 index 0000000..bf3c9e3 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditDetail.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.Tables.Audit; + +[NoAudit] +[Table("AuditDetails", Schema = "Audit")] +public class AuditDetail : IId +{ + [Key] + public long Id { get; set; } + [Required] + public long UserId { get; set; } + [Required] + public string UserDisplayName { get; set; } = string.Empty; + [Required, MaxLength(50)] + public string Type { get; set; } = string.Empty; + [Required] + public DateTimeOffset DateTime { get; set; } + [Required] + public string Fields { get; set; } = string.Empty; + [Required] + public string Comment { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditDrillHierarchy.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditDrillHierarchy.cs new file mode 100644 index 0000000..39ce4bf --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditDrillHierarchy.cs @@ -0,0 +1,40 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Audit.Tables.Audit; + +[NoAudit] +[Table("AuditDrillHierarchies", Schema = "Audit")] +public class AuditDrillHierarchy : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public long ParentAuditDrillDownEntityId { get; set; } + + [Required] + public long ChildAuditDrillDownEntityId { get; set; } + + [ForeignKey(nameof(ParentAuditDrillDownEntityId))] + public virtual AuditEntry ParentAuditDrillDownEntity { get; set; } = null!; + + [ForeignKey(nameof(ChildAuditDrillDownEntityId))] + public virtual AuditEntry ChildAuditDrillDownEntity { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasOne(x => x.ParentAuditDrillDownEntity) + .WithMany() + .OnDelete(DeleteBehavior.NoAction); + + modelBuilder.Entity() + .HasOne(x => x.ChildAuditDrillDownEntity) + .WithMany() + .OnDelete(DeleteBehavior.NoAction); + } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditEntry.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditEntry.cs new file mode 100644 index 0000000..f98cdb1 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/AuditEntry.cs @@ -0,0 +1,33 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Audit.Tables.Audit; + +[NoAudit] +[Table("AuditEntries", Schema = "Audit")] +public class AuditEntry : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public long AuditLogId { get; set; } + + [Required] + public string EntityName { get; set; } = null!; + + [Required] + public string PrimaryKey { get; set; } = string.Empty; + + [Required] + public string? DisplayName { get; set; } = string.Empty; + + [Required] + public bool IsPrimary { get; set; } = false; + + + [ForeignKey(nameof(AuditLogId))] + public virtual AuditDetail AuditLog { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/IAudit.cs b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/IAudit.cs new file mode 100644 index 0000000..75c6b74 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/Tables/Audit/IAudit.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Audit.Tables.Audit; + +public interface IAudit : IDatabaseAudit +{ + DbSet AuditDetails { get; set; } + + DbSet AuditEntries { get; set; } + + DbSet AuditDrillHierarchies { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Audit/e-suite.Database.Audit/e-suite.Database.Audit.csproj b/e-suite.Database.Audit/e-suite.Database.Audit/e-suite.Database.Audit.csproj new file mode 100644 index 0000000..da15b35 --- /dev/null +++ b/e-suite.Database.Audit/e-suite.Database.Audit/e-suite.Database.Audit.csproj @@ -0,0 +1,28 @@ + + + + net10.0 + e_suite.Database.Audit + enable + enable + + + + 1701;1702;NU1904 + + + + 1701;1702;NU1904 + + + + + + + + + + + + + diff --git a/e-suite.Database.Audit/nuget.config b/e-suite.Database.Audit/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Database.Audit/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Database.Core/.gitattributes b/e-suite.Database.Core/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Database.Core/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Database.Core/.gitignore b/e-suite.Database.Core/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Database.Core/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Database.Core/.runsettings b/e-suite.Database.Core/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Database.Core/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Database.Core/README.md b/e-suite.Database.Core/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Database.Core/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Database.Core/azure-pipelines.yml b/e-suite.Database.Core/azure-pipelines.yml new file mode 100644 index 0000000..a42897b --- /dev/null +++ b/e-suite.Database.Core/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Database.Core/e-suite.Database.Core.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '40' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/DeltaUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/DeltaUnitTests.cs new file mode 100644 index 0000000..6c9bbaf --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/DeltaUnitTests.cs @@ -0,0 +1,200 @@ +using NUnit.Framework; +using e_suite.Database.Core.Helpers; +using Microsoft.EntityFrameworkCore; +using Moq; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class DeltaUnitTests +{ + private static DbSet GetQueryableMockDbSet(List sourceList) where T : class + { + var queryable = sourceList.AsQueryable(); + + var dbSet = new Mock>(); + dbSet.As>().Setup(m => m.Provider).Returns(queryable.Provider); + dbSet.As>().Setup(m => m.Expression).Returns(queryable.Expression); + dbSet.As>().Setup(m => m.ElementType).Returns(queryable.ElementType); + dbSet.As>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); + dbSet.Setup(d => d.Add(It.IsAny())).Callback((s) => sourceList.Add(s)); + dbSet.Setup(d => d.RemoveRange(It.IsAny>())).Callback>( + items => + { + foreach (var item in items) + { + sourceList.Remove(item); + } + }); + + dbSet.Setup(d => d.AddRangeAsync(It.IsAny>(), It.IsAny())).Callback, CancellationToken>( + (items, cancellationToken) => + { + foreach (var item in items) + { + cancellationToken.ThrowIfCancellationRequested(); + sourceList.Add(item); + } + }); + + return dbSet.Object; + } + + private static void AssertListContents(IReadOnlyList listToTest, List list) + { + foreach (var item in list) + Assert.That(listToTest.Contains(item), Is.True); + } + private static void AssertDeltaMatches(IReadOnlyList> actualResultMatches, List list) + { + foreach (var item in actualResultMatches) + { + var originalIndex = list.IndexOf(item.Original); + var updatedIndex = list.IndexOf(item.Updated); + + Assert.That(originalIndex, Is.GreaterThan(-1)); + Assert.That(updatedIndex, Is.GreaterThan(-1)); + Assert.That(originalIndex, Is.EqualTo(updatedIndex)); + } + } + + [Test] + public void CalculateDelta_CalculatesAdditions() + { + //Arrange + var originalList = new List(); + var updatedList = new List { "a", "b", "c" }; + + //Act + var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase ); + + //Assert + Assert.That(actualResult.Additions.Count, Is.EqualTo(3)); + AssertListContents(actualResult.Additions, ["a", "b", "c"]); + Assert.That(actualResult.Deletions.Count, Is.EqualTo(0)); + Assert.That(actualResult.Matches.Count, Is.EqualTo(0)); + } + + [Test] + public void CalculateDelta_CalculatesDeletions() + { + //Arrange + var originalList = new List { "d", "e", "f" }; + var updatedList = new List(); + + //Act + var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase); + + //Assert + Assert.That(actualResult.Additions.Count, Is.EqualTo(0)); + Assert.That(actualResult.Deletions.Count, Is.EqualTo(3)); + AssertListContents(actualResult.Deletions, ["d", "e", "f"]); + Assert.That(actualResult.Matches.Count, Is.EqualTo(0)); + } + + [Test] + public void CalculateDelta_CalculatesMatches() + { + //Arrange + var originalList = new List { "g", "h", "i" }; + var updatedList = new List { "g", "h", "i" }; + + //Act + var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase); + + //Assert + Assert.That(actualResult.Additions.Count, Is.EqualTo(0)); + Assert.That(actualResult.Deletions.Count, Is.EqualTo(0)); + Assert.That(actualResult.Matches.Count, Is.EqualTo(3)); + AssertDeltaMatches(actualResult.Matches, ["g", "h", "i"]); + } + + [Test] + public void CalculateDelta_CanCalulateACombinationOfAddDeleteAndMatch() + { + //Arrange + var originalList = new List { "j", "k", "l", "p", "q", "r" }; + var updatedList = new List { "m", "n", "o", "p", "q", "r" }; + + //Act + var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase); + + //Assert + Assert.That(actualResult.Additions.Count, Is.EqualTo(3)); + AssertListContents(actualResult.Additions, ["m", "n", "o"]); + Assert.That(actualResult.Deletions.Count, Is.EqualTo(3)); + AssertListContents(actualResult.Deletions, ["j", "k", "l"]); + Assert.That(actualResult.Matches.Count, Is.EqualTo(3)); + AssertDeltaMatches(actualResult.Matches, ["p", "q", "r"]); + } + + [Test] + public void CalculateDelta_CancellationTokenThrowsExceptionWhenCancelled() + { + //Arrange + var originalList = new List { "j", "k", "l", "p", "q", "r" }; + var updatedList = new List { "m", "n", "o", "p", "q", "r" }; + + CancellationTokenSource cts = new(); + CancellationToken cancellationToken = cts.Token; + cts.Cancel(); + + //Assert + Assert.Throws(() => + { + //Act + var actualResult = Delta.CalculateDelta(updatedList, originalList, + StringComparer.InvariantCultureIgnoreCase, cancellationToken); + }); + } + + [Test] + public void UpdateDbSetAsync_TokenCancelled_ThrowsException() + { + //Arrange + var originalList = new List { "j", "k", "l", "p", "q", "r" }; + var updatedList = new List { "m", "n", "o", "p", "q", "r" }; + CancellationTokenSource cts = new(); + CancellationToken cancellationToken = cts.Token; + + var delta = Delta.CalculateDelta(updatedList, originalList, + StringComparer.InvariantCultureIgnoreCase, cancellationToken); + + + cts.Cancel(); + + var mockDBSet = GetQueryableMockDbSet(originalList); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await delta.UpdateDbSetAsync(mockDBSet, cancellationToken); + }); + } + + [Test] + public async Task UpdateDbSetAsync_UpdateCompletes_UpdatedDBSetContainsExpectedValues() + { + //Arrange + var sourceList = new List { "j", "k", "l", "p", "q", "r" }; + var mockDbSet = GetQueryableMockDbSet(sourceList); + + var originalList = new List(sourceList); + var updatedList = new List { "m", "n", "o", "p", "q", "r" }; + CancellationTokenSource cts = new(); + CancellationToken cancellationToken = cts.Token; + + var delta = Delta.CalculateDelta(updatedList, originalList, + StringComparer.InvariantCultureIgnoreCase, cancellationToken); + + //Act + await delta.UpdateDbSetAsync(mockDbSet, cancellationToken); + + //Assert + Assert.That(mockDbSet.Count(), Is.EqualTo(6) ); + + foreach (var entry in mockDbSet) + Assert.That(updatedList.Contains(entry), Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/EmailUserActionTypeUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/EmailUserActionTypeUnitTests.cs new file mode 100644 index 0000000..146355d --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/EmailUserActionTypeUnitTests.cs @@ -0,0 +1,26 @@ +using e_suite.Database.Core.Models; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class EmailUserActionTypeUnitTests +{ + [Test] + public void EmailUserActionType_PasswordReset_Is0() + { + Assert.That((int)EmailUserActionType.PasswordReset, Is.EqualTo(0)); + } + + [Test] + public void EmailUserActionType_DisableAuthenticator_Is1() + { + Assert.That((int)EmailUserActionType.DisableAuthenticator, Is.EqualTo(1)); + } + + [Test] + public void EmailUserActionType_ConfirmEmailAddress_Is2() + { + Assert.That((int)EmailUserActionType.ConfirmEmailAddress, Is.EqualTo(2)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/GeneralIdExtensionsUnitTest.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/GeneralIdExtensionsUnitTest.cs new file mode 100644 index 0000000..baf3e68 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/GeneralIdExtensionsUnitTest.cs @@ -0,0 +1,105 @@ +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class GeneralIdExtensionsUnitTest +{ + private class TestClass : IGeneralId + { + public long Id { get; set; } + public Guid Guid { get; set; } + } + + private TestClass testClass { get; set; } = null!; + + [SetUp] + public void Setup() + { + testClass = new TestClass + { + Guid = new Guid("a6576bfa-364e-4453-9f58-0448f0045cc3"), + Id = 2356234 + }; + } + + [Test] + public void IsMatch_WhenIdAndGuidNull_ReturnsFalse() + { + //Arrange + var comparitor = new GeneralIdRef(); + + //Act + var actualResult = testClass.IsMatch(comparitor); + + //Assert + Assert.That(actualResult, Is.False); + } + + [Test] + public void IsMatch_WhenGuidDoesNotMatch_ReturnsFalse() + { + //Arrange + var comparitor = new GeneralIdRef + { + Guid = new Guid("5a05a440-9a55-4e80-91b4-314e1b287182") + }; + + //Act + var actualResult = testClass.IsMatch(comparitor); + + //Assert + Assert.That(actualResult, Is.False); + } + + [Test] + public void IsMatch_WhenIdDoesNotMatch_ReturnsFalse() + { + //Arrange + var comparitor = new GeneralIdRef + { + Id = 9328475 + }; + + //Act + var actualResult = testClass.IsMatch(comparitor); + + //Assert + Assert.That(actualResult, Is.False); + } + + [Test] + public void IsMatch_WhenGuidMatches_ReturnsTrue() + { + //Arrange + var comparitor = new GeneralIdRef + { + Guid = testClass.Guid + }; + + //Act + var actualResult = testClass.IsMatch(comparitor); + + //Assert + Assert.That(actualResult, Is.True); + } + + [Test] + public void IsMatch_WhenIdMatches_ReturnsTrue() + { + //Arrange + var comparitor = new GeneralIdRef + { + Id = testClass.Id + }; + + //Act + var actualResult = testClass.IsMatch(comparitor); + + //Assert + Assert.That(actualResult, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/GeneralIdRefExtensionsUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/GeneralIdRefExtensionsUnitTests.cs new file mode 100644 index 0000000..2583f16 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/GeneralIdRefExtensionsUnitTests.cs @@ -0,0 +1,82 @@ +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class GeneralIdRefExtensionsUnitTests +{ + private class TestClass : IGeneralId + { + public long Id { get; set; } + public Guid Guid { get; set; } + } + + [Test] + public void ToGeneralIdRef_Converting_AssignsCorrectValues() + { + //Arrange + var testClass = new TestClass + { + Id = 100, + Guid = new Guid("{3795F04F-8536-4C56-9FF6-D46649998253}") + }; + + //Act + var actualResult = testClass.ToGeneralIdRef(); + + //Assert + Assert.That(actualResult!.Id, Is.EqualTo(testClass.Id)); + Assert.That(actualResult!.Guid, Is.EqualTo(testClass.Guid)); + } + + [Test] + public void ToGeneralIdRef_WhenNull_AssignsNull() + { + //Arrange + TestClass testClass = null!; + + //Act + var actualResult = testClass.ToGeneralIdRef(); + + //Assert + Assert.That(actualResult, Is.Null); + } + + [Test] + public void ToGeneralIfRefs_ConvertingList_AssignsCorrectValues() + { + //Arrange + var testList = new List + { + new TestClass + { + Id = 100, + Guid = new Guid("C2E5764F-086B-496A-AB8C-CCBCF37BE8A5") + }, + new TestClass + { + Id = 101, + Guid = new Guid("6EB942AD-0118-4941-BEDC-6E4B8FA79579") + }, + new TestClass + { + Id = 102, + Guid = new Guid("3c8348e4-96ff-44f6-b421-64fd176b1bfb") + } + }; + + //Act + var actualResult = testList.ToGeneralIfRefs().ToList(); + + //Assert + Assert.That(actualResult.Count, Is.EqualTo(testList.Count)); + Assert.That(actualResult[0].Id, Is.EqualTo(testList[0].Id)); + Assert.That(actualResult[0].Guid, Is.EqualTo(testList[0].Guid)); + Assert.That(actualResult[1].Id, Is.EqualTo(testList[1].Id)); + Assert.That(actualResult[1].Guid, Is.EqualTo(testList[1].Guid)); + Assert.That(actualResult[2].Id, Is.EqualTo(testList[2].Id)); + Assert.That(actualResult[2].Guid, Is.EqualTo(testList[2].Guid)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/Tables/TableWithKey.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/Tables/TableWithKey.cs new file mode 100644 index 0000000..71c55d0 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/Tables/TableWithKey.cs @@ -0,0 +1,25 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.UnitTests.Helpers.Tables; + +[Table("TableWithKey", Schema = "StandAlone")] +public class TableWithKey +{ + [Key] + public long Id { get; set; } + + [Required] public int TotalTimeMS { get; set; } + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasData(new TableWithKey + { + Id = 1, + TotalTimeMS = 2000 + } + ); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/TestDbContext.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/TestDbContext.cs new file mode 100644 index 0000000..ba44a9f --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/TestDbContext.cs @@ -0,0 +1,15 @@ +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.UnitTests.Helpers.Tables; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.UnitTests.Helpers; + +public class TestDbContext : SunDatabaseEntityContext +{ + public TestDbContext(DbContextOptions options, IClock clock) : base(options, clock) + { + } + + public DbSet TableWithKey { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/TestDbContextFactory.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/TestDbContextFactory.cs new file mode 100644 index 0000000..1dd3049 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Helpers/TestDbContextFactory.cs @@ -0,0 +1,45 @@ +using System.Data.Common; +using eSuite.Core.Clock; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.UnitTests.Helpers; + +public class TestDbContextFactory : IDisposable +{ + //private const string _connectionString = "Data Source = InMemorySample; Mode=Memory;Cache=Shared"; + private const string _connectionString = "DataSource=:memory:"; + + private DbConnection _connection = null!; + + private DbContextOptions CreateOptions() + { + return new DbContextOptionsBuilder() + .UseSqlite(_connection).Options; + } + + public TestDbContext CreateContext(IClock clock) + { + if (_connection == null) + { + _connection = new SqliteConnection(_connectionString); + _connection.Open(); + + var options = CreateOptions(); + using var context = new TestDbContext(options, clock); + context.Database.EnsureCreated(); + } + + return new TestDbContext(CreateOptions(), clock); + } + + public void Dispose() + { + if (_connection != null) + { + _connection.Dispose(); + _connection = null!; + } + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Models/TestCargo.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Models/TestCargo.cs new file mode 100644 index 0000000..5ae1c77 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/Models/TestCargo.cs @@ -0,0 +1,11 @@ +using e_suite.Database.Core.Models; + +namespace e_suite.Database.Core.UnitTests.Models; + +public class TestCargo : IGeneralId +{ + public long Id { get; set; } + public Guid Guid { get; set; } + + public string Name { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsIEnumerableUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsIEnumerableUnitTests.cs new file mode 100644 index 0000000..1af44a9 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsIEnumerableUnitTests.cs @@ -0,0 +1,225 @@ +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Extensions.Exceptions; +using e_suite.Database.Core.UnitTests.Models; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class QueryableExtensionsIEnumerableUnitTests +{ + [Test] + public void FindByGeneralIdRef_IdNotFound_ReturnsNull() + { + //Arrange + var items = new List + { + new() + { + Id = 1, + Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"), + Name = "Test Item" + } + }.AsQueryable(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = 100 + }; + + var list = new List + { + generalIdRef + }; + + var result = items.FindByGeneralIdRef(list).ToArray(); + + //Assert + Assert.That(result.Length, Is.Zero); + } + + [Test] + public void FindByGeneralIdRef_IdFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }.AsQueryable(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId + }; + + var list = new List + { + generalIdRef + }; + + var result = items.FindByGeneralIdRef(list).ToArray(); + + //Assert + Assert.That(result.Length, Is.EqualTo(1)); + Assert.That(result.First(), Is.EqualTo(testItem)); + } + + [Test] + public void FindByGeneralIdRef_GuidFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }.AsQueryable(); + + //Act + var generalIdRef = new GeneralIdRef + { + Guid = keyGuid + }; + + var list = new List + { + generalIdRef + }; + + var result = items.FindByGeneralIdRef(list).ToArray(); + + //Assert + Assert.That(result.Length, Is.EqualTo(1)); + Assert.That(result.First(), Is.EqualTo(testItem)); + } + + [Test] + public void FindByGeneralIdRef_IdAndGuid_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }.AsQueryable(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId, + Guid = keyGuid + }; + + var list = new List + { + generalIdRef + }; + + var result = items.FindByGeneralIdRef(list).ToArray(); + + //Assert + Assert.That(result.Length, Is.EqualTo(1)); + Assert.That(result.First(), Is.EqualTo(testItem)); + } + + [Test] + public void FindByGeneralIdRef_WrongIdAndCorrectGuid_ReturnsNullWhenIdDoesNotExist() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }.AsQueryable(); + + var generalIdRef = new GeneralIdRef + { + Id = keyId + 1, + Guid = keyGuid + }; + + var list = new List + { + generalIdRef + }; + + //Act & Assert + Assert.Throws(() => { var result = items.FindByGeneralIdRef(list).ToArray(); }); + } + + [Test] + public void FindByGeneralIdRef_CorrectIdAndWrongGuid_ThrowsExpectedException() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + var wrongGuid = new Guid("{C3BC5BAC-39F9-40B8-A191-0F25CD366FE4}"); + + var testItem = new TestCargo + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }.AsQueryable(); + + //Act and Assert + var generalIdRef = new GeneralIdRef + { + Id = keyId, + Guid = wrongGuid + }; + + var list = new List + { + generalIdRef + }; + + var result = Assert.Throws(() => { items.FindByGeneralIdRef(list).ToArray(); }); + + Assert.That(result?.Message, Is.EqualTo($"The retrieved guid {keyGuid} does not match the expected guid {wrongGuid}")); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsIQueryableUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsIQueryableUnitTests.cs new file mode 100644 index 0000000..8073428 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsIQueryableUnitTests.cs @@ -0,0 +1,261 @@ +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Extensions.Exceptions; +using e_suite.Database.Core.UnitTests.Models; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using NUnit.Framework; + + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class QueryableExtensionsIQueryableUnitTests +{ + + [Test] + public async Task FindByGeneralIdRefAsync_IdNotFound_ReturnsNull() + { + //Arrange + var data = new List + { + new() + { + Id = 1, + Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"), + Name = "Test Item" + } + }; + + var mock = data.BuildMock(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = 100 + }; + + var result = await mock.AsQueryable().FindByGeneralIdRefAsync(generalIdRef, default); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public async Task FindByGeneralIdRefAsync_IdFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testIrem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testIrem + }; + + var mock = items.BuildMock(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId + }; + + var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default); + + //Assert + Assert.That(result, Is.EqualTo(testIrem)); + } + + [Test] + public async Task FindByGeneralIdRefAsync_GuidFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testIrem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testIrem + }; + + var mock = items.BuildMock(); + + //Act + var generalIdRef = new GeneralIdRef + { + Guid = keyGuid + }; + + var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default); + + //Assert + Assert.That(result, Is.EqualTo(testIrem)); + } + + [Test] + public async Task FindByGeneralIdRefAsync_IdAndGuid_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testIrem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testIrem + }; + + var mock = items.BuildMock(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId, + Guid = keyGuid + }; + + var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default); + + //Assert + Assert.That(result, Is.EqualTo(testIrem)); + } + + [Test] + public async Task FindByGeneralIdRefAsync_WrongIdAndCorrectGuid_ReturnsNullWhenIdDoesNotExist() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testIrem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testIrem + }; + + var mock = items.BuildMock(); + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId + 1, + Guid = keyGuid + }; + + var result = await mock.FindByGeneralIdRefAsync(generalIdRef, default); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public void FindByGeneralIdRefAsync_CorrectIfAndWrongGuid_ThrowsExpectedException() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + var wrongGuid = new Guid("{C3BC5BAC-39F9-40B8-A191-0F25CD366FE4}"); + + var testItem = new TestCargo + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + var mock = items.BuildMock(); + + //Act and Assert + var generalIdRef = new GeneralIdRef + { + Id = keyId, + Guid = wrongGuid + }; + + var result = Assert.ThrowsAsync(async () => { await mock.FindByGeneralIdRefAsync(generalIdRef, default); }); + + Assert.That(result?.Message, Is.EqualTo($"The retrieved guid {keyGuid} does not match the expected guid {wrongGuid}")); + } + + [Test] + public async Task FindByIdAsync_IdNotFound_ReturnsNull() + { + //Arrange + var items = new List + { + new() + { + Id = 1, + Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"), + Name = "Test Item" + } + }; + + var mock = items.BuildMock(); + + //Act + var result = await mock.FindByIdAsync(100, default); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public async Task FindByIdAsync_IdFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testIrem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testIrem + }; + + var mock = items.BuildMock(); + + //Act + var result = await mock.FindByIdAsync(keyId, default); + + //Assert + Assert.That(result, Is.EqualTo(testIrem)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsUnitTests.cs new file mode 100644 index 0000000..b45ed2d --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/QueryableExtensionsUnitTests.cs @@ -0,0 +1,242 @@ +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Extensions.Exceptions; +using e_suite.Database.Core.UnitTests.Models; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class QueryableExtensionsUnitTests +{ + [Test] + public void FindByGeneralIdRef_IdNotFound_ReturnsNull() + { + //Arrange + var items = new List + { + new() + { + Id = 1, + Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"), + Name = "Test Item" + } + }; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = 100 + }; + + var result = items.FindByGeneralIdRef(generalIdRef); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public void FindByGeneralIdRef_IdFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId + }; + + var result = items.FindByGeneralIdRef(generalIdRef); + + //Assert + Assert.That(result, Is.EqualTo(testItem)); + } + + [Test] + public void FindByGeneralIdRef_GuidFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + //Act + var generalIdRef = new GeneralIdRef + { + Guid = keyGuid + }; + + var result = items.FindByGeneralIdRef(generalIdRef); + + //Assert + Assert.That(result, Is.EqualTo(testItem)); + } + + [Test] + public void FindByGeneralIdRef_IdAndGuid_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId, + Guid = keyGuid + }; + + var result = items.FindByGeneralIdRef(generalIdRef); + + //Assert + Assert.That(result, Is.EqualTo(testItem)); + } + + [Test] + public void FindByGeneralIdRef_WrongIdAndCorrectGuid_ReturnsNullWhenIdDoesNotExist() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + //Act + var generalIdRef = new GeneralIdRef + { + Id = keyId + 1, + Guid = keyGuid + }; + + var result = items.FindByGeneralIdRef(generalIdRef); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public void FindByGeneralIdRef_CorrectIdAndWrongGuid_ThrowsExpectedException() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + var wrongGuid = new Guid("{C3BC5BAC-39F9-40B8-A191-0F25CD366FE4}"); + + var testItem = new TestCargo + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + //Act and Assert + var generalIdRef = new GeneralIdRef + { + Id = keyId, + Guid = wrongGuid + }; + + var result = Assert.Throws(() => { items.FindByGeneralIdRef(generalIdRef); }); + + Assert.That(result?.Message, Is.EqualTo($"The retrieved guid {keyGuid} does not match the expected guid {wrongGuid}")); + } + + [Test] + public void FindById_IdNotFound_ReturnsNull() + { + //Arrange + var items = new List + { + new() + { + Id = 1, + Guid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"), + Name = "Test Item" + } + }; + + //Act + var result = items.FindById(100); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public void FindById_IdFound_ReturnsExpectedValue() + { + //Arrange + var keyId = 1; + var keyGuid = new Guid("{F81F58DB-ACB0-404E-B5DB-C480DE3F2016}"); + + var testItem = new TestCargo() + { + Id = keyId, + Guid = keyGuid, + Name = "Test Item" + }; + + var items = new List + { + testItem + }; + + //Act + var result = items.FindById(keyId); + + //Assert + Assert.That(result, Is.EqualTo(testItem)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/RepositoryBaseUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/RepositoryBaseUnitTests.cs new file mode 100644 index 0000000..f158817 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/RepositoryBaseUnitTests.cs @@ -0,0 +1,68 @@ +using Moq; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class RepositoryBaseUnitTests +{ + private Mock _mockDatabaseContext = null!; + + private RepositoryBase repositoryBase = null!; + + [SetUp] + public void Setup() + { + _mockDatabaseContext = new Mock(); + + repositoryBase = new RepositoryBase(_mockDatabaseContext.Object); + } + + private bool taskHasBeenCalled; + + private Task Action() + { + taskHasBeenCalled = true; + return Task.CompletedTask; + } + + [Test] + public async Task TransactionAsync_CalledWithAction_CallsTheVersionInTheDatabaseContext() + { + //Arrange + taskHasBeenCalled = false; + + _mockDatabaseContext.Setup(x => x.TransactionAsync(It.IsAny)).Returns(Action()); + + //Act + await repositoryBase.TransactionAsync(Action); + + //Assert + Assert.That(taskHasBeenCalled, Is.True); + _mockDatabaseContext.Verify( x => x.TransactionAsync(It.IsAny>()), Times.Once); + } + + private bool funcHasBeenCalled; + + private Task Function() + { + funcHasBeenCalled = true; + return Task.FromResult(true); + } + + [Test] + public async Task TransactionAsync_CalledWithFunction_CallsTheVersionInTheDatabaseContext() + { + //Arrange + funcHasBeenCalled = false; + + _mockDatabaseContext.Setup(x => x.TransactionAsync(It.IsAny>>())).Returns(Function()); + + //Act + var result = await repositoryBase.TransactionAsync(Function); + + //Assert + Assert.That(funcHasBeenCalled, Is.True); + Assert.That(result, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/SunDatabaseEntityContextUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/SunDatabaseEntityContextUnitTests.cs new file mode 100644 index 0000000..ea527c4 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/SunDatabaseEntityContextUnitTests.cs @@ -0,0 +1,195 @@ +using e_suite.Database.Core.UnitTests.Helpers; +using e_suite.Database.Core.UnitTests.Helpers.Tables; +using eSuite.Core.Clock; +using Moq; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class SunDatabaseEntityContextUnitTests +{ + protected TestDbContextFactory testDbContextFactory = null!; + protected Mock _clockMock = null!; + public DateTimeOffset TestNow = DateTimeOffset.Now; + + protected TestDbContext TestDbContext = null!; + + [SetUp] + public void Setup() + { + testDbContextFactory = new TestDbContextFactory(); + + _clockMock = new Mock(); + _clockMock.Setup(x => x.GetNow).Returns(() => TestNow); + + TestDbContext = testDbContextFactory.CreateContext(_clockMock.Object); + } + + [Test] + public void OnModelCreating_Executes_WithoutExceptions() + { + //Arrange + //Act + // dealt with by the Setup method, as this ensures the database is created. + + //Assert + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); + } + + [Test] + public async Task TransActionAsyncAction_Executing_CodeRunsInATransaction() + { + //Arrange + Guid? transactionId = null; + + + //Act + await TestDbContext.TransactionAsync(async () => + { + transactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; + await TestDbContext.SaveChangesAsync(); + }); + + //Assert + Assert.That(transactionId, Is.Not.Null); //Was in a transaction when the code was executed + Assert.That(TestDbContext.Database.CurrentTransaction?.TransactionId, Is.Null); //No longer in a transaction + } + + [Test] + public async Task TransActionAsyncAction_AlreadyInTransaction_DoesNotStartAnotherTransaction() + { + //Arrange + Guid? transactionId = null; + Guid? innerTransactionId = null; + + await TestDbContext.TransactionAsync(async () => + { + transactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; + + //Act + await TestDbContext.TransactionAsync( async () => + { + innerTransactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; + await TestDbContext.SaveChangesAsync(); + }); + }); + + //Assert + Assert.That(transactionId, Is.Not.Null); //Was in a transaction when the code was executed + Assert.That(innerTransactionId, Is.EqualTo(transactionId)); //The inner transaction is the same as the outer transaction. Transaction inception is not allowed. + } + + [Test] + public async Task TransActionAsyncAction_InsertedRecordWithNoException_TransactionCompletes() + { + //Arrange + var newItem = new TableWithKey() + { + Id = 2, + TotalTimeMS = 5000 + }; + + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); + + //Act + await TestDbContext.TransactionAsync(async () => + { + TestDbContext.TableWithKey.Add(newItem); + await TestDbContext.SaveChangesAsync(); + }); + + //Assert + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(2)); + } + + [Test] + public async Task TransActionAsyncAction_InsertedRecordThenException_TransactionIsRolledback() + { + //Arrange + var newItem = new TableWithKey() + { + Id = 2, + TotalTimeMS = 5000 + }; + + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); + + //Act + try + { + await TestDbContext.TransactionAsync(async () => + { + TestDbContext.TableWithKey.Add(newItem); + await TestDbContext.SaveChangesAsync(); + + throw new Exception("Testing rollback"); + }); + } + catch + { + //This was supposed to happen + } + + //Assert + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); + } + + [Test] + public async Task TransActionAsyncFunc_Executing_CodeRunsInATransaction() + { + //Arrange + Guid? transactionId = null; + + //Act + var result = await TestDbContext.TransactionAsync(async () => + { + transactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; + + await TestDbContext.SaveChangesAsync(); + return true; + }); + + //Assert + Assert.That(result, Is.True); + Assert.That(transactionId, Is.Not.Null); //Was in a transaction when the code was executed + Assert.That(TestDbContext.Database.CurrentTransaction?.TransactionId, Is.Null); //No longer in a transaction + } + + [Test] + public async Task TransActionAsyncFunc_InsertedRecordThenException_TransactionIsRolledback() + { + //Arrange + var newItem = new TableWithKey() + { + Id = 2, + TotalTimeMS = 5000 + }; + + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); + + //Act + try + { + var result = await TestDbContext.TransactionAsync(async () => + { + TestDbContext.TableWithKey.Add(newItem); + await TestDbContext.SaveChangesAsync(); + + throw new Exception("Testing rollback"); + +#pragma warning disable CS0162 + //This code will never be hit because this is a test, but it's needed so that the code will compile. + return 1; +#pragma warning restore CS0162 + }); + } + catch + { + //This was supposed to happen + } + + //Assert + Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/TableDefinitionUnitTests.cs b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/TableDefinitionUnitTests.cs new file mode 100644 index 0000000..7a384e3 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/TableDefinitionUnitTests.cs @@ -0,0 +1,172 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.Reflection; +using e_suite.Database.Audit.Attributes; +using Microsoft.EntityFrameworkCore; +using NUnit.Framework; + +namespace e_suite.Database.Core.UnitTests; + +[TestFixture] +public class TableDefinitionUnitTests +{ + protected List Tables { get; set; } = []; + + private static CustomAttributeData? FindAttribute(Type type, Type attributeType) + { + return type.CustomAttributes.FirstOrDefault(customAttribute => attributeType.IsAssignableFrom(customAttribute.AttributeType)); + } + + private static CustomAttributeData? FindAttribute(PropertyInfo propertyInfo, Type type) + { + return propertyInfo.CustomAttributes.FirstOrDefault(customAttribute => type.IsAssignableFrom(customAttribute.AttributeType)); + } + + private static List CompileAcceptableTableNames(string tableName) + { + var result = new List(); + + var lastCharactor = tableName[^1..]; + var lastTwoCharactors = tableName[^2..]; + + if (lastTwoCharactors.Equals("ey", StringComparison.InvariantCultureIgnoreCase)) + { + result.Add(tableName + "s"); + } + else if (lastCharactor.Equals("y", StringComparison.InvariantCultureIgnoreCase)) + { + result.Add(string.Concat(tableName.AsSpan(0, tableName.Length - 1), "ies")); + } + else if (lastCharactor.Equals("s", StringComparison.InvariantCultureIgnoreCase)) + { + result.Add(tableName); + } + else + { + result.Add(tableName + "s"); + } + + return result; + } + + [SetUp] + public void Setup() + { + Tables.Clear(); + var databaseContextClass = typeof(EsuiteDatabaseDbContext); + + var properties = databaseContextClass.GetProperties(); + foreach (var property in properties) + { + if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)) + { + Tables.Add(property.PropertyType.GenericTypeArguments[0]); + } + } + } + + + [Test] + public void Table_PropertyHasAuditParentAttribute_AlsoHasForeignKey() + { + //Arrange + //Act + foreach (var table in Tables) + { + //Need to check all the properties of the table to see if it contains the AuditParent Custom property + var properties = table.GetProperties(); + + foreach (var property in properties) + { + if (FindAttribute(property, typeof(AuditParentAttribute)) != null) + { + //Assert + if (FindAttribute(property, typeof(ForeignKeyAttribute)) != null) + Assert.Pass($"Property {property.Name} Has both AuditParentAttribute And ForeignKey attribute"); + else + Assert.Fail($"Property {property.Name} Has AuditParentAttribute but is missing the ForeignKey attribute"); + } + } + } + } + + [Test] + public void Table_TableName_IsSetConsistently() + { + //Arrange + //Act + foreach (var table in Tables) + { + //Need to check all the properties of the table to see if it contains the AuditParent Custom property + var tableAttribute = FindAttribute(table, typeof(TableAttribute)); + + //Assert + if (tableAttribute == null) + Assert.Fail($"Table \"{table.Name}\" Missing the TableNameAttribute"); + + var acceptableTableNames = CompileAcceptableTableNames(table.Name); + + var tableName = tableAttribute?.ConstructorArguments[0].Value?.ToString() ?? string.Empty; + + if (!acceptableTableNames.Contains(tableName)) + Assert.Fail($"Table name \"{tableName}\" for class \"{table.Name}\" does not conform to the naming standards"); + + var schemaName = tableAttribute!.NamedArguments.Single( x=> x.MemberName == "Schema"); + var tableNamespace = table.Namespace?.Split("."); + if (tableNamespace != null && tableNamespace.Last() != schemaName.TypedValue.Value?.ToString()) + Assert.Fail($"Schema name for \"{table.Name}\" set incorrectly is currently \"{schemaName.TypedValue.Value}\" but should be \"{tableNamespace}\""); + } + } + + [Test] + public void Table_AuditedTables_HasLastUpdated() + { + //Arrange + //Act + foreach (var table in Tables) + { + //Assert + var tableAttribute = FindAttribute(table, typeof(TableAttribute)); + if (tableAttribute == null) + continue; + + //Need to check all the properties of the table to see if it contains the AuditParent Custom property + var noAuditAttribute = FindAttribute(table, typeof(NoAuditAttribute)); + if (noAuditAttribute != null) + continue; + + var foundLastUpdated = false; + var properties = table.GetProperties(); + foreach (var property in properties) + { + if (FindAttribute(property, typeof(AuditLastUpdatedAttribute)) != null) + { + foundLastUpdated = true; + break; + } + } + + if (!foundLastUpdated) + Assert.Fail($"Table {table.Name} Missing {nameof(AuditLastUpdatedAttribute)}"); + } + } + + [Test] + public void Table_ForeignKeysAreVirtual() + { + //Arrange + //Act + foreach (var table in Tables) + { + var properties = table.GetProperties(); + foreach (var property in properties) + { + if (FindAttribute(property, typeof(ForeignKeyAttribute)) != null) + { + //Assert + if (!property.GetAccessors().Any( x=> x.IsVirtual)) + Assert.Fail($"Table {table.Name}.{property.Name} is not virtual"); + } + } + } + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core.UnitTests/e-suite.Database.Core.UnitTests.csproj b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/e-suite.Database.Core.UnitTests.csproj new file mode 100644 index 0000000..7ef5fc4 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.UnitTests/e-suite.Database.Core.UnitTests.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + e_suite.Database.Core.UnitTests + enable + enable + + + + + + + + + + + + + + + + + diff --git a/e-suite.Database.Core/e-suite.Database.Core.sln b/e-suite.Database.Core/e-suite.Database.Core.sln new file mode 100644 index 0000000..510275c --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.Core", "e-suite.Database.Core\e-suite.Database.Core.csproj", "{552EF4B6-7A2D-4CAA-84A7-CE07403CAE9D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{3ED25E52-1C88-47DC-9C88-989AAE71792F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{F82C1B9A-1E78-4970-ADCB-E571AE30B717}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.Core.UnitTests", "e-suite.Database.Core.UnitTests\e-suite.Database.Core.UnitTests.csproj", "{7E005F1D-E7AF-4DBB-B7E4-BFC56A5BC410}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {552EF4B6-7A2D-4CAA-84A7-CE07403CAE9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {552EF4B6-7A2D-4CAA-84A7-CE07403CAE9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {552EF4B6-7A2D-4CAA-84A7-CE07403CAE9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {552EF4B6-7A2D-4CAA-84A7-CE07403CAE9D}.Release|Any CPU.Build.0 = Release|Any CPU + {7E005F1D-E7AF-4DBB-B7E4-BFC56A5BC410}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E005F1D-E7AF-4DBB-B7E4-BFC56A5BC410}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E005F1D-E7AF-4DBB-B7E4-BFC56A5BC410}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E005F1D-E7AF-4DBB-B7E4-BFC56A5BC410}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F82C1B9A-1E78-4970-ADCB-E571AE30B717} = {3ED25E52-1C88-47DC-9C88-989AAE71792F} + {7E005F1D-E7AF-4DBB-B7E4-BFC56A5BC410} = {F82C1B9A-1E78-4970-ADCB-E571AE30B717} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C8473C5B-E3E1-4D52-893D-B46B44A127A1} + EndGlobalSection +EndGlobal diff --git a/e-suite.Database.Core/e-suite.Database.Core/EsuiteDatabaseDbContext.cs b/e-suite.Database.Core/e-suite.Database.Core/EsuiteDatabaseDbContext.cs new file mode 100644 index 0000000..66e52c5 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/EsuiteDatabaseDbContext.cs @@ -0,0 +1,67 @@ +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.Contacts; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Diagnostics; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.Database.Core.Tables.Mail; +using e_suite.Database.Core.Tables.Miscellaneous; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.Database.Core.Tables.Sequences; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Database.Core.Tables.Workflow; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core; + +public class EsuiteDatabaseDbContext : SunDatabaseEntityContext, IEsuiteDatabaseDbContext +{ + public EsuiteDatabaseDbContext(DbContextOptions options, IClock clock) : base(options, clock) + { + } + + public DbSet Users { get; set; } = null!; + public DbSet SsoProviders { get; set; } = null!; + public DbSet SingleUseGuids { get; set; } + public DbSet EmailUserActions { get; set; } = null!; + public DbSet FailedAccessAttempts { get; set; } = null!; + public DbSet ExceptionLogs { get; set; } = null!; + public DbSet PerformanceReports { get; set; } = null!; + public DbSet PerformanceThresholds { get; set; } = null!; + public DbSet Sequences { get; set; } = null!; + public DbSet CustomFields { get; set; } = null!; + public DbSet CustomFieldSequences { get; set; } = null!; + public DbSet CustomFieldFormTemplate { get; set; } = null!; + public DbSet CustomFieldGlossaries { get; set; } = null!; + public DbSet CustomFieldNumber { get; set; } = null!; + public DbSet CustomFieldText { get; set; } = null!; + public DbSet FormTemplates { get; set; } = null!; + public DbSet FormTemplateVersions { get; set; } = null!; + public DbSet FormFieldInstances { get; set; } = null!; + public DbSet FormInstances { get; set; } = null!; + public DbSet Glossaries { get; set; } = null!; + public DbSet GlossaryCustomFields { get; set; } = null!; + public DbSet GlossaryCustomFieldValues { get; set; } = null!; + public DbSet Organisations { get; set; } = null!; + public DbSet Sites { get; set; } = null!; + public DbSet Specifications { get; set; } = null!; + public DbSet Contacts {get; set; } = null!; + public DbSet OrganisationContacts { get; set; } = null!; + public DbSet SiteContacts {get; set; } = null!; + public DbSet Domains { get; set; } = null!; + public DbSet Roles { get; set; } + public DbSet UserRoles { get; set; } + public DbSet RoleAccess { get; set; } +#pragma warning disable IDE1006 // Naming Styles + protected DbSet userAccess { get; set; } = null!; +#pragma warning restore IDE1006 // Naming Styles + public IQueryable UserAccess => userAccess.AsNoTracking(); + public DbSet MailTemplates { get; set; } = null!; + public DbSet ExternalSystems { get; set; } + public DbSet ExternalKeys { get; set; } + public DbSet Workflows { get; set; } + public DbSet WorkflowVersions { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Extensions/Exceptions/GuidMismatchException.cs b/e-suite.Database.Core/e-suite.Database.Core/Extensions/Exceptions/GuidMismatchException.cs new file mode 100644 index 0000000..03b25d1 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Extensions/Exceptions/GuidMismatchException.cs @@ -0,0 +1,24 @@ +namespace e_suite.Database.Core.Extensions.Exceptions; + +public class GuidMismatchException : Exception +{ + public GuidMismatchException() : base() + { + + } + + public GuidMismatchException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public GuidMismatchException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Extensions/Exceptions/IdMismatchException.cs b/e-suite.Database.Core/e-suite.Database.Core/Extensions/Exceptions/IdMismatchException.cs new file mode 100644 index 0000000..b18782a --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Extensions/Exceptions/IdMismatchException.cs @@ -0,0 +1,24 @@ +namespace e_suite.Database.Core.Extensions.Exceptions; + +public class IdMismatchException : Exception +{ + public IdMismatchException() : base() + { + + } + + public IdMismatchException(string? message) + : base(message) + { + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public IdMismatchException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Extensions/GeneralIdExceptions.cs b/e-suite.Database.Core/e-suite.Database.Core/Extensions/GeneralIdExceptions.cs new file mode 100644 index 0000000..795e683 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Extensions/GeneralIdExceptions.cs @@ -0,0 +1,18 @@ +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Database.Core.Extensions; + +public static class GeneralIdExtensions +{ + public static bool IsMatch( this IGeneralId generalId, IGeneralIdRef generalIdRef) + { + if ((generalIdRef.Id != null) && (generalId.Id == generalIdRef.Id)) + return true; + + if ((generalIdRef.Guid != null) && (generalId.Guid == generalIdRef.Guid)) + return true; + + return false; + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Extensions/GeneralIdRefExtensions.cs b/e-suite.Database.Core/e-suite.Database.Core/Extensions/GeneralIdRefExtensions.cs new file mode 100644 index 0000000..e270f55 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Extensions/GeneralIdRefExtensions.cs @@ -0,0 +1,28 @@ +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Database.Core.Extensions; + +public static class GeneralIdRefExtensions +{ + public static GeneralIdRef? ToGeneralIdRef(this IGeneralId? generalId) + { + if (generalId == null) + return null; + + return new GeneralIdRef + { + Id = generalId.Id, + Guid = generalId.Guid + }; + } + + public static IEnumerable ToGeneralIfRefs(this IEnumerable generalIds) + { + return generalIds.Select(generalId => new GeneralIdRef + { + Id = generalId.Id, + Guid = generalId.Guid + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Extensions/QueryableExtensions.cs b/e-suite.Database.Core/e-suite.Database.Core/Extensions/QueryableExtensions.cs new file mode 100644 index 0000000..4ba243a --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Extensions/QueryableExtensions.cs @@ -0,0 +1,76 @@ +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Extensions.Exceptions; +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Extensions; + +public static class QueryableExtensions +{ + private static void DoubleCheckGuid(IGeneralIdRef id, TEntity? entity) where TEntity : class, IGeneralId + { + if (entity != null) + { + if (id.Guid != null) + { + if (entity.Guid != id.Guid) + throw new GuidMismatchException( + $"The retrieved guid {entity.Guid} does not match the expected guid {id.Guid}"); + } + + if (id.Id != null) + { + if (entity.Id != id.Id) + throw new IdMismatchException($"The retrieved guid {entity.Id} does not match the expected guid {id.Id}"); + } + } + } + + public static TEntity? FindByGeneralIdRef(this IEnumerable enumerable, IGeneralIdRef id) where TEntity : class, IGeneralId + { + var entity = id.Id != null ? enumerable.SingleOrDefault(x => x.Id == id.Id) : enumerable.SingleOrDefault(x => x.Guid == id.Guid); + + DoubleCheckGuid(id, entity); + + return entity; + } + + public static async Task FindByGeneralIdRefAsync(this IQueryable queryable, IGeneralIdRef id, CancellationToken cancellationToken) where TEntity : class, IGeneralId + { + var entity = id.Id != null ? await queryable.SingleOrDefaultAsync(x => x.Id == id.Id, cancellationToken) : await queryable.SingleOrDefaultAsync(x => x.Guid == id.Guid, cancellationToken); + + DoubleCheckGuid(id, entity); + + return entity; + } + + public static IEnumerable FindByGeneralIdRef(this IQueryable queryable, IEnumerable generalIdRefs) where TEntity : class, IGeneralId + { + var idRefs = generalIdRefs as IGeneralIdRef[] ?? generalIdRefs.ToArray(); + var guids = idRefs.Select(y => y.Guid); + var ids = idRefs.Select(y => y.Id); + + foreach (var entity in queryable.Where(x => guids.Contains(x.Guid) || ids.Contains(x.Id))) + { + var idRef = idRefs.First(x => x.Guid == entity.Guid || x.Id == entity.Id); + DoubleCheckGuid(idRef, entity); + + yield return entity; + } + } + + public static TEntity? FindById(this IEnumerable enumerable, long id) where TEntity : class, IId + { + var entity = enumerable.SingleOrDefault(x => x.Id == id); + + return entity; + } + + public static async Task FindByIdAsync(this IQueryable queryable, long id, CancellationToken cancellationToken) where TEntity : class, IId + { + var entity = await queryable.SingleOrDefaultAsync(x => x.Id == id, cancellationToken); + + return entity; + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/GlobalSuppressions.cs b/e-suite.Database.Core/e-suite.Database.Core/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Database.Core/e-suite.Database.Core/Helpers/Delta.cs b/e-suite.Database.Core/e-suite.Database.Core/Helpers/Delta.cs new file mode 100644 index 0000000..a8aacee --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Helpers/Delta.cs @@ -0,0 +1,86 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Helpers; + +public class Delta where T : class +{ + private Delta(List deletions, List additions, IReadOnlyList> matches) + { + Deletions = deletions; + Additions = additions; + Matches = matches; + } + + public IReadOnlyList Additions { get; } + public IReadOnlyList Deletions { get; } + public IReadOnlyList> Matches { get; } + + + public static Delta CalculateDelta(IEnumerable updated, IEnumerable original, IComparer keyComparer) + { + return CalculateDelta(updated, original, keyComparer, CancellationToken.None); + } + + public static Delta CalculateDelta(IEnumerable updated, IEnumerable original, IComparer keyComparer, CancellationToken? cancellationToken) + { + var deletions = new List(); + foreach (var originalItem in original) + { + var found = false; + foreach (var updatedItem in updated) + { + cancellationToken?.ThrowIfCancellationRequested(); + if (keyComparer.Compare(updatedItem, originalItem) != 0) + continue; + + found = true; + break; + } + + if (!found) + deletions.Add(originalItem); + } + + var additions = new List(); + var matches = new List>(); + + foreach (var updatedItem in updated) + { + var found = false; + foreach (var originalItem in original) + { + cancellationToken?.ThrowIfCancellationRequested(); + if (keyComparer.Compare(updatedItem, originalItem) != 0) + continue; + + matches.Add(new() + { + Updated = updatedItem, + Original = originalItem + }); + + found = true; + break; + } + + if (!found) + additions.Add(updatedItem); + } + + return new Delta(deletions, additions, matches); + } + + public async Task UpdateDbSetAsync(DbSet dbSet, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + dbSet.RemoveRange(Deletions); + + foreach (var match in Matches) + { + cancellationToken.ThrowIfCancellationRequested(); + dbSet.Update(match.Original); + } + + await dbSet.AddRangeAsync(Additions, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Helpers/DeltaMatch.cs b/e-suite.Database.Core/e-suite.Database.Core/Helpers/DeltaMatch.cs new file mode 100644 index 0000000..640bf18 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Helpers/DeltaMatch.cs @@ -0,0 +1,7 @@ +namespace e_suite.Database.Core.Helpers; + +public class DeltaMatch +{ + public T Updated { get; set; } = default!; + public T Original { get; set; } = default!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Helpers/SunDatabaseEntityContext.cs b/e-suite.Database.Core/e-suite.Database.Core/Helpers/SunDatabaseEntityContext.cs new file mode 100644 index 0000000..b60cf9e --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Helpers/SunDatabaseEntityContext.cs @@ -0,0 +1,88 @@ +using System.Reflection; +using e_suite.Database.Audit; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Helpers; + +public class SunDatabaseEntityContext : AuditableEntityContext, IDatabaseCore +{ + public SunDatabaseEntityContext(DbContextOptions options, IClock clock) : base(options, clock) + { + } + + public virtual Task InitializeAsync() + { + return Task.CompletedTask; + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + var type = GetType(); + + var publicProperties = type.GetProperties(); + + foreach (var property in publicProperties) + { + if (!property.PropertyType.IsGenericType) + continue; + + if (property.PropertyType.GetGenericTypeDefinition() != typeof(DbSet<>)) + continue; + + var table = property.PropertyType.GenericTypeArguments[0]; + + var tableMethod = table.GetMethod("OnModelCreating", BindingFlags.Static | BindingFlags.Public); + + if (tableMethod != null) + tableMethod.Invoke(null, new object?[] { modelBuilder }); + } + } + + public async Task TransactionAsync(Func> action) + { + if (Database.CurrentTransaction != null) + return await action(); + + await using var transaction = await Database.BeginTransactionAsync(); + + try + { + var result = await action(); + + await transaction.CommitAsync(); + + return result; + } + catch (Exception) + { + await transaction.RollbackAsync(); + throw; + } + } + + public async Task TransactionAsync(Func action) + { + if (Database.CurrentTransaction != null) + { + await action(); + return; + } + + await using var transaction = await Database.BeginTransactionAsync(); + + try + { + await action(); + + await transaction.CommitAsync(); + } + catch (Exception) + { + await transaction.RollbackAsync(); + throw; + } + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/IDatabaseCore.cs b/e-suite.Database.Core/e-suite.Database.Core/IDatabaseCore.cs new file mode 100644 index 0000000..2a39036 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/IDatabaseCore.cs @@ -0,0 +1,13 @@ +using e_suite.Database.Audit; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace e_suite.Database.Core; + +public interface IDatabaseCore : IDatabaseAudit +{ + EntityEntry Entry(TEntity entity) where TEntity : class; + + Task TransactionAsync(Func> action); + + Task TransactionAsync(Func action); +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/IEsuiteDatabaseDbContext.cs b/e-suite.Database.Core/e-suite.Database.Core/IEsuiteDatabaseDbContext.cs new file mode 100644 index 0000000..4be899c --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/IEsuiteDatabaseDbContext.cs @@ -0,0 +1,21 @@ +using e_suite.Database.Audit.Tables.Audit; +using e_suite.Database.Core.Tables.Contacts; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Diagnostics; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.Database.Core.Tables.Mail; +using e_suite.Database.Core.Tables.Miscellaneous; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.Database.Core.Tables.Sequences; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Database.Core.Tables.Workflow; + +namespace e_suite.Database.Core; + +public interface IEsuiteDatabaseDbContext : IAudit, ISentinel, IUserManager, IDiagnostics, ISequences, ICustomFields, IForm, IGlossaries, IPrinter, IContact, IMail, IDomain, IMiscellaneous, IWorkflowManager +{ + +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/IRepository.cs b/e-suite.Database.Core/e-suite.Database.Core/IRepository.cs new file mode 100644 index 0000000..fc72ee6 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/IRepository.cs @@ -0,0 +1,7 @@ +namespace e_suite.Database.Core; + +public interface IRepository +{ + Task TransactionAsync(Func> func); + Task TransactionAsync(Func action); +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/ContactType.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/ContactType.cs new file mode 100644 index 0000000..7d57678 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/ContactType.cs @@ -0,0 +1,8 @@ +namespace e_suite.Database.Core.Models +{ + public enum ContactType + { + Primary, + NotPrimary + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/EmailUserActionType.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/EmailUserActionType.cs new file mode 100644 index 0000000..01ac341 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/EmailUserActionType.cs @@ -0,0 +1,8 @@ +namespace e_suite.Database.Core.Models; + +public enum EmailUserActionType +{ + PasswordReset, + DisableAuthenticator, + ConfirmEmailAddress +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/ICustomFieldValue.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/ICustomFieldValue.cs new file mode 100644 index 0000000..15f1d5c --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/ICustomFieldValue.cs @@ -0,0 +1,15 @@ +using e_suite.Database.Core.Tables.CustomFields; + +namespace e_suite.Database.Core.Models; + +public interface ICustomFieldValue +{ + long Id { get; set; } + long CustomFieldId { get; set; } + long Index { get; set; } + string Value { get; set; } + string DisplayValue { get; set; } + Guid Guid { get; set; } + + CustomField CustomField { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/IGeneralId.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/IGeneralId.cs new file mode 100644 index 0000000..40daa0d --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/IGeneralId.cs @@ -0,0 +1,8 @@ +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Core.Models; + +public interface IGeneralId : IId +{ + public Guid Guid { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/IName.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/IName.cs new file mode 100644 index 0000000..8b9dae2 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/IName.cs @@ -0,0 +1,6 @@ +namespace e_suite.Database.Core.Models; + +public interface IName +{ + public string Name { get; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/ISoftDeletable.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/ISoftDeletable.cs new file mode 100644 index 0000000..f9c9050 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/ISoftDeletable.cs @@ -0,0 +1,6 @@ +namespace e_suite.Database.Core.Models; + +public interface ISoftDeletable +{ + public bool Deleted { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/OrganisationStatus.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/OrganisationStatus.cs new file mode 100644 index 0000000..22b0eee --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/OrganisationStatus.cs @@ -0,0 +1,9 @@ +namespace e_suite.Database.Core.Models +{ + public enum OrganisationStatus + { + Active, + Pending, + Blocked + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Models/TaskDefinition.cs b/e-suite.Database.Core/e-suite.Database.Core/Models/TaskDefinition.cs new file mode 100644 index 0000000..d09b269 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Models/TaskDefinition.cs @@ -0,0 +1,8 @@ +namespace e_suite.Database.Core.Models; + +public class TaskDefinition +{ + public string Type { get; set; } = string.Empty; + public int Order { get; set; } + public Dictionary? Config { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/RepositoryBase.cs b/e-suite.Database.Core/e-suite.Database.Core/RepositoryBase.cs new file mode 100644 index 0000000..49f5079 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/RepositoryBase.cs @@ -0,0 +1,21 @@ +namespace e_suite.Database.Core; + +public class RepositoryBase : IRepository +{ + protected readonly IEsuiteDatabaseDbContext DatabaseDbContext; + + public RepositoryBase(IEsuiteDatabaseDbContext databaseDbContext) + { + DatabaseDbContext = databaseDbContext; + } + + public async Task TransactionAsync(Func> func) + { + return await DatabaseDbContext.TransactionAsync(func); + } + + public async Task TransactionAsync(Func action) + { + await DatabaseDbContext.TransactionAsync(action); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Contacts/Contact.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Contacts/Contact.cs new file mode 100644 index 0000000..901e200 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Contacts/Contact.cs @@ -0,0 +1,29 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.Contacts +{ + [DisplayName("Contact")] + [Table("Contacts", Schema = "Contacts")] + [Index(nameof(Id), IsUnique = true)] + [Index(nameof(Guid), IsUnique = true)] + public class Contact : IGeneralId + { + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } + + [AuditName] + [Required] + public string JCard { get; set; } = string.Empty; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Contacts/IContact.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Contacts/IContact.cs new file mode 100644 index 0000000..19d1bb7 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Contacts/IContact.cs @@ -0,0 +1,9 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Contacts +{ + public interface IContact : IDatabaseCore + { + DbSet Contacts { get; set; } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomField.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomField.cs new file mode 100644 index 0000000..2437f8e --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomField.cs @@ -0,0 +1,61 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using eSuite.Core.CustomFields; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.CustomFields; + +[DisplayName("Custom Field")] +[Table("CustomFields", Schema = "CustomFields")] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class CustomField : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [Required] public FieldType FieldType { get; set; } = FieldType.Text; + + [Required] + [DefaultValue(1)] + public long MinEntries { get; set; } = 1; + + [DefaultValue(1)] + public long? MaxEntries { get; set; } = 1; + + [Required] + public string DefaultValue { get; set; } = string.Empty; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new CustomField + { + Id = 1, + Name = "Print Specification Form Template", + Deleted = false, + Guid = new Guid("{8D910089-3079-4A29-ABAD-8DDF82DB6DBB}"), + FieldType = FieldType.FormTemplate, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty, + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldFormTemplate.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldFormTemplate.cs new file mode 100644 index 0000000..576344c --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldFormTemplate.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Tables.Forms; + +namespace e_suite.Database.Core.Tables.CustomFields; + +[DisplayName("Custom Field Form Template")] +[Table("CustomFieldFormTemplates", Schema = "CustomFields")] +public class CustomFieldFormTemplate : IId +{ + [Key] + public long Id { get; set; } + + public long CustomFieldId { get; set; } + + public long FormTemplateId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; + + [ForeignKey(nameof(FormTemplateId))] + public virtual FormTemplate FormTemplate { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldGlossary.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldGlossary.cs new file mode 100644 index 0000000..f928fbb --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldGlossary.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Tables.Glossaries; + +namespace e_suite.Database.Core.Tables.CustomFields; + +[DisplayName("Custom Field Glossary")] +[Table("CustomFieldGlossaries", Schema = "CustomFields")] +public class CustomFieldGlossary : IId +{ + [Key] + public long Id { get; set; } + + public long CustomFieldId { get; set; } + + public long GlossaryId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; + + [ForeignKey(nameof(GlossaryId))] + public virtual Glossary Glossary { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldNumber.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldNumber.cs new file mode 100644 index 0000000..ecbb844 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldNumber.cs @@ -0,0 +1,31 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.CustomFields; + +[DisplayName("Custom Field Number")] +[Table("CustomFieldNumbers", Schema = "CustomFields")] +public class CustomFieldNumber : IId +{ + [Key] + public long Id { get; set; } + + public long CustomFieldId { get; set; } + [Precision(28, 8)] + public decimal? MinimumValue { get; set; } + [Precision(28, 8)] + public decimal? MaximumValue { get; set; } + [Precision(28, 8)] + public decimal? Step { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldSequence.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldSequence.cs new file mode 100644 index 0000000..04e6fec --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldSequence.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Core.Tables.CustomFields; + +[DisplayName("Custom Field Sequence")] +[Table("CustomFieldSequences", Schema = "CustomFields")] +public class CustomFieldSequence : IId +{ + [Key] + public long Id { get; set; } + + public long CustomFieldId { get; set; } + + public long SequenceId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; + + [ForeignKey(nameof(SequenceId))] + public virtual Sequences.Sequence Sequence { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldText.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldText.cs new file mode 100644 index 0000000..cfce648 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/CustomFieldText.cs @@ -0,0 +1,26 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.CustomFields; + +[DisplayName("Custom Field Text")] +[Table("CustomFieldTexts", Schema = "CustomFields")] +public class CustomFieldText : IId +{ + [Key] + public long Id { get; set; } + + public long CustomFieldId { get; set; } + + public bool? MultiLine { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/ICustomFields.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/ICustomFields.cs new file mode 100644 index 0000000..fc9f559 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/CustomFields/ICustomFields.cs @@ -0,0 +1,18 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.CustomFields; + +public interface ICustomFields : IDatabaseCore +{ + DbSet CustomFields { get; set; } + + DbSet CustomFieldSequences { get; set; } + + DbSet CustomFieldFormTemplate { get; set; } + + DbSet CustomFieldGlossaries { get; set; } + + DbSet CustomFieldNumber { get; set; } + + DbSet CustomFieldText { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/ExceptionLog.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/ExceptionLog.cs new file mode 100644 index 0000000..dbe07ae --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/ExceptionLog.cs @@ -0,0 +1,32 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.Diagnostics; + +[NoAudit] +[Table("ExceptionLogs", Schema = "Diagnostics")] +public class ExceptionLog : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public string Application { get; set; } = string.Empty; + + [Required] + public string ExceptionJson { get; set; } = string.Empty; + + [Required] + public string Message { get; set; } = string.Empty; + + [Required] + public string StackTrace { get; set; } = string.Empty; + + [Required] + public string SupportingData { get; set;} = string.Empty; + + [Required] + public DateTimeOffset OccuredAt { get; set; } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/IDiagnostics.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/IDiagnostics.cs new file mode 100644 index 0000000..3249687 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/IDiagnostics.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Diagnostics; + +public interface IDiagnostics : IDatabaseCore +{ + DbSet PerformanceReports { get; set; } + + DbSet PerformanceThresholds { get; set; } + + DbSet ExceptionLogs { get; set; } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/PerformanceReport.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/PerformanceReport.cs new file mode 100644 index 0000000..c1e894d --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/PerformanceReport.cs @@ -0,0 +1,38 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; + +namespace e_suite.Database.Core.Tables.Diagnostics; + +[NoAudit] +[Table("PerformanceReports", Schema = "Diagnostics")] +public class PerformanceReport : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public string Host { get; set; } = null!; + + [Required] + public string ControllerName { get; set; } = null!; + + [Required] + public string ActionName { get; set; } = null!; + + [Required] + public string RequestType { get; set; } = null!; + + [Required] + public string ActionParameters { get; set; } = null!; + + [Required] + public DateTimeOffset StartDateTime { get; set; } + + [Required] + public string Timings { get; set; } = null!; + + [Required] + public int TotalTimeMS { get; set; } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/PerformanceThreshold.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/PerformanceThreshold.cs new file mode 100644 index 0000000..a07a24a --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Diagnostics/PerformanceThreshold.cs @@ -0,0 +1,40 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Diagnostics; + +[NoAudit] +[Table("PerformanceThresholds", Schema = "Diagnostics")] +public class PerformanceThreshold +{ + + [Required] + public string ControllerName { get; set; } = null!; + + [Required] + public string ActionName { get; set; } = null!; + + [Required] + public string RequestType { get; set; } = null!; + + [Required] + public int TotalTimeMS { get; set; } + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(x => new { x.ControllerName, x.ActionName, x.RequestType }); + + modelBuilder.Entity() + .HasData(new PerformanceThreshold + { + ActionName = string.Empty, + ControllerName = string.Empty, + RequestType = string.Empty, + TotalTimeMS = 2000 + } + ); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/Domain.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/Domain.cs new file mode 100644 index 0000000..89df7a8 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/Domain.cs @@ -0,0 +1,64 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Domain; + +[DisplayName("Domain")] +[Table("Domains", Schema = "Domain")] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class Domain : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [MaxLength(16)] //Taken from Domain.Hostname in sunrise + public string SunriseHostname { get; set; } = string.Empty; + + [MaxLength(128)] //Taken from PublicApiKeys.AppId in sunrise + public string SunriseAppId { get; set; } = string.Empty; + + [MaxLength(16)] //Taken from Category.Id in sunrise + public string SunriseCategoryId { get; set; } = string.Empty; + + public long? SigmaId { get; set; } + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + + [DefaultValue(null)] + public long? SsoProviderId { get; set; } = null!; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(SsoProviderId))] + public virtual SsoProvider? SsoProvider { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new Domain + { + Id = 1, + Guid = new Guid("{4EB1B0C7-E81B-4C9D-BA91-384ED47A1CF9}"), + Name = "Sun-Strategy", + Deleted = false, + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/IDomain.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/IDomain.cs new file mode 100644 index 0000000..ba8f746 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/IDomain.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Domain; + +public interface IDomain : IDatabaseCore +{ + DbSet Domains { get; set; } + DbSet Roles { get; set; } + DbSet UserRoles { get; set; } + DbSet RoleAccess { get; set; } + IQueryable UserAccess { get; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/Role.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/Role.cs new file mode 100644 index 0000000..f0928a2 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/Role.cs @@ -0,0 +1,83 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Domain; + +[DisplayName("Role")] +[Table("Roles", Schema = "Domain")] +[Index(nameof(Guid), IsUnique = true)] +[Index(nameof(DomainId), nameof(Name), IsUnique = true)] +public class Role : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + /// + /// Super users are automatically allows to do anything on any domain + /// + [Required] + public bool IsSuperUser { get; set; } = false; + + /// + /// Administrators are automatically allowed to do anything on the Domain specified by DomainId + /// + [Required] + public bool IsAdministrator { get; set; } = false; + + [Required] + public bool CanDelete { get; set; } = true; + + [Required] + [DefaultValue(1)] + public long DomainId { get; set; } + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(DomainId))] + public virtual Domain Domain { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new Role + { + Id = 1, + Guid = new Guid("{32D65817-4DE4-4BD5-912E-2B33054A2171}"), + Name = "Super Users", + IsSuperUser = true, + IsAdministrator = false, + CanDelete = false, + DomainId = 1, + Deleted = false, + }); + + modelBuilder.Entity().HasData(new Role + { + Id = 2, + Guid = new Guid("{2F77F57C-FE2C-4A36-AD17-5D902AFC86CB}"), + Name = "Administrators", + IsSuperUser = false, + IsAdministrator = true, + CanDelete = false, + DomainId = 1, + Deleted = false, + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/RoleAccess.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/RoleAccess.cs new file mode 100644 index 0000000..3500aee --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/RoleAccess.cs @@ -0,0 +1,34 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Domain; + +[DisplayName("RoleAccess")] +[Table("RoleAccess", Schema = "Domain")] +public class RoleAccess +{ + [Required] + public long RoleId { get; set; } + + /// + /// Contains the Enum value for the security access entry + /// + [Required] + public int AccessKey { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(RoleId))] + public virtual Role Role { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(gc => new { gc.RoleId, gc.AccessKey }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/UserAccess.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/UserAccess.cs new file mode 100644 index 0000000..4b0a228 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/UserAccess.cs @@ -0,0 +1,37 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Core.Tables.UserManager; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Domain; + +[DisplayName("UserAccess")] +[Table("UserAccess", Schema = "Domain")] +[Keyless] +public class UserAccess +{ + [Required] + public long UserId { get; set; } + + [Required] + public long DomainId { get; set; } + + /// + /// Contains the Enum value for the security access entry + /// + [Required] + public int AccessKey { get; set; } + + [ForeignKey(nameof(UserId))] + public virtual User User { get; set; } = null!; + + [ForeignKey(nameof(DomainId))] + public virtual Domain Domain { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasNoKey(); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/UserRole.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/UserRole.cs new file mode 100644 index 0000000..c691f58 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Domain/UserRole.cs @@ -0,0 +1,52 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Domain; + +[DisplayName("UserRoles")] +[Table("UserRoles", Schema = "Domain")] +public class UserRole : ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public long UserId { get; set; } + + [Required] + public long RoleId { get; set; } + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(UserId))] + public virtual User User { get; set; } = null!; + + [AuditParent] + [ForeignKey(nameof(RoleId))] + public virtual Role Role { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasAlternateKey(gc => new { gc.UserId , gc.RoleId }); + + modelBuilder.Entity().HasData(new UserRole + { + Id = 1, + UserId = 1, + RoleId = 1 + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormFieldInstance.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormFieldInstance.cs new file mode 100644 index 0000000..022c910 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormFieldInstance.cs @@ -0,0 +1,47 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.CustomFields; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Forms; + +[DisplayName("Form Field Instance")] +[Table("FormFieldInstances", Schema = "Forms")] +[Index(nameof(Guid), IsUnique = true)] +[Index(nameof(FormInstanceId), nameof(CustomFieldId), nameof(Index), IsUnique = true)] +public class FormFieldInstance : IGeneralId, ICustomFieldValue +{ + [Key] + public long Id { get; set; } + + [Required] + public long FormInstanceId { get; set; } + + [Required] + public long CustomFieldId { get; set; } + + [Required] + public long Index { get; set; } + + [Required] + public string Value { get; set; } = string.Empty; + + [Required] + public string DisplayValue { get; set; } = string.Empty; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(FormInstanceId))] + public virtual FormInstance FormInstance { get; set; } = null!; + + [ForeignKey(nameof(CustomFieldId))] + public CustomField CustomField { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormInstance.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormInstance.cs new file mode 100644 index 0000000..e001c2b --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormInstance.cs @@ -0,0 +1,45 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Forms; + +[DisplayName("Form Instance")] +[Table("FormInstances", Schema = "Forms")] +[Index(nameof(Guid), IsUnique = true)] +public class FormInstance : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public long FormTemplateVersionId { get; set; } + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [ForeignKey(nameof(FormTemplateVersionId))] + public virtual FormTemplateVersion FormTemplateVersion { get; set; } = null!; + + public ICollection FormFields { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasMany(x => x.FormFields) + .WithOne(x => x.FormInstance) + .HasForeignKey(x => x.FormInstanceId) + .HasPrincipalKey(x => x.Id); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormTemplate.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormTemplate.cs new file mode 100644 index 0000000..fcadaaf --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormTemplate.cs @@ -0,0 +1,36 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Forms; + +[DisplayName("Form Template")] +[Table("FormTemplates", Schema = "Forms")] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class FormTemplate : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + public ICollection Versions { get; set; } = (Collection) []; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormTemplateVersion.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormTemplateVersion.cs new file mode 100644 index 0000000..68798ae --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/FormTemplateVersion.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Forms; + +[DisplayName("Form Template Version")] +[Table("FormTemplateVersions", Schema = "Forms")] +[Index(nameof(TemplateId), nameof(Version), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class FormTemplateVersion : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public long TemplateId { get; set; } + + [Required] + public long Version { get; set; } = 0; + + [AuditName] + [NotMapped] + public string DisplayName => $"{Template.Name} V{Version}"; + + [Required] + public string FormDefinition { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(TemplateId))] + public virtual FormTemplate Template { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/IForm.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/IForm.cs new file mode 100644 index 0000000..0d0a24f --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Forms/IForm.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Forms; + +public interface IForm : IDatabaseCore +{ + DbSet FormTemplates { get; set; } + + DbSet FormTemplateVersions { get; set; } + + DbSet FormFieldInstances { get; set; } + + DbSet FormInstances { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/Glossary.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/Glossary.cs new file mode 100644 index 0000000..472beef --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/Glossary.cs @@ -0,0 +1,75 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Glossaries; + +[DisplayName("Glossary")] +[Table("Glossaries", Schema = "Glossaries")] +[Index(nameof(Id), nameof(ParentId), IsUnique = true)] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class Glossary : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + public long? ParentId { get; set; } + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [ForeignKey(nameof(ParentId))] + [AuditParent] + public virtual Glossary Parent { get; set; } = null!; + + public Collection CustomFieldDefinitions { get; set; } = []; + + public Collection CustomFieldValues { get; set; } = []; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new Glossary + { + Id = 1, + Guid = new Guid("{FA6566F8-B4B0-48C5-9985-336C9284796E}"), + Name = "System", + Deleted = false, + ParentId = null + }); + + modelBuilder.Entity().HasData(new Glossary + { + Id = 2, + Guid = new Guid("{90C48CF1-1A2B-4A76-B30B-260ECB149CCC}"), + Name = "Domain", + Deleted = false, + ParentId = null + }); + + modelBuilder.Entity().HasData(new Glossary + { + Id = 3, + Guid = new Guid("{35EB8C23-4528-49A7-A798-B8BAE3B06DAF}"), + Name = "Print Specifications", + Deleted = false, + ParentId = 1 + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/GlossaryCustomField.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/GlossaryCustomField.cs new file mode 100644 index 0000000..8206036 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/GlossaryCustomField.cs @@ -0,0 +1,53 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Tables.CustomFields; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Glossaries; + +[DisplayName("Glossary Custom Field")] +[Table("GlossaryCustomFields", Schema = "Glossaries")] +public class GlossaryCustomField : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public long GlossaryId { get; set; } + + [Required] + public long CustomFieldId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(GlossaryId))] + public virtual Glossary Glossary { get; set; } = null!; + + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasAlternateKey(gc => new { gc.GlossaryId, gc.CustomFieldId }); + + modelBuilder.Entity() + .HasOne(gc => gc.Glossary) + .WithMany(gc => gc.CustomFieldDefinitions) + .HasForeignKey(gc => gc.GlossaryId); + + + modelBuilder.Entity() + .HasData(new GlossaryCustomField + { + Id = 1, + GlossaryId = 3, + CustomFieldId = 1 + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/GlossaryCustomFieldValue.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/GlossaryCustomFieldValue.cs new file mode 100644 index 0000000..9935611 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/GlossaryCustomFieldValue.cs @@ -0,0 +1,58 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.CustomFields; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Glossaries; + +[DisplayName("Glossary Custom Field Value")] +[Table("GlossaryCustomFieldValues", Schema = "Glossaries")] +[Index(nameof(GlossaryId), nameof(CustomFieldId), nameof(Index), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class GlossaryCustomFieldValue : IGeneralId, ICustomFieldValue +{ + [Key] + public long Id { get; set; } + + [Required] + public long GlossaryId { get; set; } + + [Required] + public long CustomFieldId { get; set; } + + [Required] + public long Index { get; set; } + + [Required] + public string Value { get; set; } = string.Empty; + + [Required] + public string DisplayValue { get; set; } = string.Empty; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(GlossaryId))] + public virtual Glossary Glossary { get; set; } = null!; + + [ForeignKey(nameof(CustomFieldId))] + public virtual CustomField CustomField { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasAlternateKey(gcfv => new { gcfv.GlossaryId, gcfv.CustomFieldId, gcfv.Index }); + + modelBuilder.Entity() + .HasOne(gcfv => gcfv.Glossary) + .WithMany(gcfv => gcfv.CustomFieldValues) + .HasForeignKey(gcfv => gcfv.GlossaryId); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/IGlossaries.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/IGlossaries.cs new file mode 100644 index 0000000..3d21058 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Glossaries/IGlossaries.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Glossaries; + +public interface IGlossaries : IDatabaseCore +{ + DbSet Glossaries { get; set; } + + DbSet GlossaryCustomFields { get; set; } + + DbSet GlossaryCustomFieldValues { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Mail/IMail.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Mail/IMail.cs new file mode 100644 index 0000000..2759b97 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Mail/IMail.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Mail; + +public interface IMail : IDatabaseCore +{ + DbSet MailTemplates { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Mail/MailTemplate.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Mail/MailTemplate.cs new file mode 100644 index 0000000..ee6a267 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Mail/MailTemplate.cs @@ -0,0 +1,94 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using eSuite.Core.MailService; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Mail; + +[DisplayName("Mail Template")] +[Table("MailTemplates", Schema = "Mail")] +[Index(nameof(DomainId), nameof(MailType), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class MailTemplate : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public MailType MailType { get; set; } + + [Required] + public string Subject { get; set; } = string.Empty; + + [Required] + public string TemplateDefinition { get; set; } = string.Empty; + + [Required] + [DefaultValue(1)] + public long DomainId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(DomainId))] + public virtual Domain.Domain Domain { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new MailTemplate + { + Id = 1, + Guid = new Guid("{32B657AF-5E17-47F3-B8DC-59580516B141}"), + DomainId = 1, + MailType = MailType.ConfirmEmailAddress, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct.", + Deleted = false, + }); + + modelBuilder.Entity().HasData(new MailTemplate + { + Id = 2, + Guid = new Guid("{77FFF2B0-DD8C-43E6-A9FD-304C79850F81}"), + DomainId = 1, + MailType = MailType.PasswordReset, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password", + Deleted = false, + }); + + modelBuilder.Entity().HasData(new MailTemplate + { + Id = 3, + Guid = new Guid("{2E2D84A5-BE1C-4E3B-A86A-BDAFED42801B}"), + DomainId = 1, + MailType = MailType.DisableAuthenticator, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication", + Deleted = false, + }); + + modelBuilder.Entity().HasData(new MailTemplate + { + Id = 4, + Guid = new Guid("{421B67C7-5F4B-4CAD-ADC5-528E2921790C}"), + DomainId = 1, + MailType = MailType.PasswordResetCompleted, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

", + Deleted = false, + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/ExternalKey.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/ExternalKey.cs new file mode 100644 index 0000000..6fcce96 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/ExternalKey.cs @@ -0,0 +1,32 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Miscellaneous; + +[NoAudit] +[Table("ExternalKeys", Schema = "Miscellaneous")] +[Index(nameof(EntityName), nameof(PrimaryKey), IsUnique = true)] +[Index(nameof(ExternalSystemId), nameof(ExternalId), IsUnique = true)] +public class ExternalKey : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public string EntityName { get; set; } = null!; + + [Required] + public string PrimaryKey { get; set; } = string.Empty; + + [Required] + public long ExternalSystemId { get; set; } + + [ForeignKey(nameof(ExternalSystemId))] + public virtual ExternalSystem ExternalSystem { get; set; } = null!; + + [Required] + public string ExternalId { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/ExternalSystem.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/ExternalSystem.cs new file mode 100644 index 0000000..9398f91 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/ExternalSystem.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Miscellaneous; + +[NoAudit] +[Table("ExternalSystems", Schema = "Miscellaneous")] +[Index(nameof(SystemName), IsUnique = true)] +public class ExternalSystem : IId +{ + [Key] + public long Id { get; set; } + + [Required] + [MaxLength(200)] + public string SystemName { get; set; } = string.Empty; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new ExternalSystem + { + Id = 1, + SystemName = "e-flow" + }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/IMiscellaneous.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/IMiscellaneous.cs new file mode 100644 index 0000000..745f798 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Miscellaneous/IMiscellaneous.cs @@ -0,0 +1,9 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Miscellaneous; + +public interface IMiscellaneous +{ + DbSet ExternalSystems { get; set; } + DbSet ExternalKeys { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/IPrinter.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/IPrinter.cs new file mode 100644 index 0000000..a574928 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/IPrinter.cs @@ -0,0 +1,13 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Printer +{ + public interface IPrinter : IDatabaseCore + { + DbSet Organisations { get; set; } + DbSet Sites { get; set; } + DbSet Specifications { get; set; } + DbSet OrganisationContacts { get; set; } + DbSet SiteContacts { get; set; } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Organisation.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Organisation.cs new file mode 100644 index 0000000..ff26fa9 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Organisation.cs @@ -0,0 +1,52 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.Printer +{ + [DisplayName("Organisation")] + [Table("Organisations", Schema = "Printer")] + [Index(nameof(Id), IsUnique = true)] + [Index(nameof(Guid), IsUnique = true)] + [Index(nameof(Name), IsUnique = true)] + public class Organisation : IGeneralId, ISoftDeletable, IName + { + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + public string Address { get; set; } = string.Empty; + + public OrganisationStatus Status { get; set; } + + [AuditSoftDelete(true)] + [Required] + + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + public ICollection Sites { get; set; } = (Collection) []; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasMany(x => x.Sites) + .WithOne(x => x.Organisation) + .HasForeignKey(x => x.OrganisationId) + .HasPrincipalKey(x => x.Id); + } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/OrganisationContact.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/OrganisationContact.cs new file mode 100644 index 0000000..52df421 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/OrganisationContact.cs @@ -0,0 +1,36 @@ +using e_suite.Database.Core.Tables.Contacts; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; +using e_suite.Database.Audit.Attributes; + +namespace e_suite.Database.Core.Tables.Printer +{ + [DisplayName("Organisation Contact")] + [Table("OrganisationContacts", Schema = "Printer")] + public class OrganisationContact + { + public long OrganisationId { get; set; } + + public long ContactId { get; set; } + + [Required] + public bool Primary { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [ForeignKey(nameof(OrganisationId))] + public virtual Organisation Organisation { get; set; } = null!; + + [ForeignKey(nameof(ContactId))] + public virtual Contact Contact { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(nameof(OrganisationId), nameof(ContactId)); + } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Site.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Site.cs new file mode 100644 index 0000000..a550498 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Site.cs @@ -0,0 +1,58 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.Printer +{ + [DisplayName("Site")] + [Table("Sites", Schema = "Printer")] + [Index(nameof(Guid), IsUnique = true)] + [Index(nameof(SigmaId), IsUnique = true)] + public class Site : IGeneralId, ISoftDeletable, IName + { + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + public string Address { get; set; } = string.Empty; + + public OrganisationStatus Status { get; set; } + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public long OrganisationId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [Required] + [ForeignKey(nameof(OrganisationId))] + public virtual Organisation Organisation { get; set; } = null!; + + public long? SigmaId { get; set; } = null!; + public ICollection Specifications { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasMany(x => x.Specifications) + .WithOne(x => x.Site) + .HasForeignKey(x => x.SiteId) + .HasPrincipalKey(x => x.Id); + } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/SiteContact.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/SiteContact.cs new file mode 100644 index 0000000..ae44df2 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/SiteContact.cs @@ -0,0 +1,38 @@ +using e_suite.Database.Core.Tables.Contacts; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; +using e_suite.Database.Audit.Attributes; + +namespace e_suite.Database.Core.Tables.Printer +{ + [DisplayName("Site Contact")] + [Table("SiteContacts", Schema = "Printer")] + public class SiteContact + { + public long SiteId { get; set; } + + public long ContactId { get; set; } + + [Required] + public bool Primary { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [ForeignKey(nameof(SiteId))] + public virtual Site Site { get; set; } = null!; + + [AuditParent] + [ForeignKey(nameof(ContactId))] + public virtual Contact Contact { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(nameof(SiteId), nameof(ContactId)); + } + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Specification.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Specification.cs new file mode 100644 index 0000000..6c81223 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Printer/Specification.cs @@ -0,0 +1,47 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.Printer +{ + [DisplayName("Specification")] + [Table("Specifications", Schema = "Printer")] + [Index(nameof(Id), IsUnique = true)] + [Index(nameof(Guid), IsUnique = true)] + [Index(nameof(SigmaId), IsUnique = true)] + public class Specification : IGeneralId, ISoftDeletable, IName + { + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + public long FormInstanceId { get; set; } + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public long SiteId { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditParent] + [Required] + [ForeignKey(nameof(SiteId))] + public virtual Site Site { get; set; } = null!; + + public long? SigmaId { get; set; } = null!; + } +} diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Sentinel/FailedAccessAttempt.FailedAccessAttempt.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sentinel/FailedAccessAttempt.FailedAccessAttempt.cs new file mode 100644 index 0000000..486a05d --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sentinel/FailedAccessAttempt.FailedAccessAttempt.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Sentinel; + +[NoAudit] +[Table("FailedAccessAttempts", Schema = "Sentinel")] +public class FailedAccessAttempt +{ + [Required, MaxLength(50)] + // ReSharper disable once InconsistentNaming + public string IPAddress { get; set; } = string.Empty; + + [Required] + public DateTimeOffset AttemptedTime { get; set; } + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasKey(p => new { p.IPAddress, p.AttemptedTime }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Sentinel/ISentinel.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sentinel/ISentinel.cs new file mode 100644 index 0000000..4842d16 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sentinel/ISentinel.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Sentinel; + +public interface ISentinel : IDatabaseCore +{ + DbSet FailedAccessAttempts { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Sequences/ISequences.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sequences/ISequences.cs new file mode 100644 index 0000000..dae8816 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sequences/ISequences.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Sequences; + +public interface ISequences : IDatabaseCore +{ + DbSet Sequences { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Sequences/Sequence.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sequences/Sequence.cs new file mode 100644 index 0000000..84066ce --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Sequences/Sequence.cs @@ -0,0 +1,53 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using eSuite.Core.Sequences; +using e_suite.Database.Core.Models; + +namespace e_suite.Database.Core.Tables.Sequences; + +[DisplayName("Sequence")] +[Table("Sequences", Schema = "Sequences")] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class Sequence : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [Required] + public Rollover Rollover { get; set; } = Rollover.Continuous; + + [Required] + [MaxLength(255)] + public string Pattern { get; set; } = string.Empty; + + [Required] + [DefaultValue(1)] + public long Seed { get; set; } = 1; + + [Required] + [DefaultValue(1)] + public long Increment { get; set; } = 1; + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } = false; + + [Required] + public Guid Guid { get; set; } = Guid.NewGuid(); + + public DateTimeOffset? LastIssueDate { get; set; } = null!; + + public long? LastIssueValue { get; set; } = null!; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/EmailUserAction.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/EmailUserAction.cs new file mode 100644 index 0000000..9f13170 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/EmailUserAction.cs @@ -0,0 +1,39 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.UserManager; + +[NoAudit] +[Table("EmailUserActions", Schema = "UserManager")] +public class EmailUserAction : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public long UserId { get; set; } + + [Required] + public EmailUserActionType EmailActionType { get; set; } + + [Required] + public Guid Token { get; set; } + + [Required] + public DateTimeOffset Created { get; set; } + + [Required] + public DateTimeOffset Expires { get; set; } + + [ForeignKey(nameof(UserId))] + public virtual User User { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasAlternateKey(u => new { u.Token, u.EmailActionType }); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/IUserManager.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/IUserManager.cs new file mode 100644 index 0000000..ebbe87a --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/IUserManager.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.UserManager; + +public interface IUserManager : IDatabaseCore +{ + DbSet Users { get; set; } + DbSet EmailUserActions { get; set; } + DbSet SsoProviders { get; set; } + DbSet SingleUseGuids { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/SingleUseGuid.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/SingleUseGuid.cs new file mode 100644 index 0000000..5fa4fc8 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/SingleUseGuid.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Audit.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.UserManager; + +[NoAudit] +[Table("SingleUseGuids", Schema = "UserManager")] +[Index(nameof(Guid), IsUnique = true)] +public class SingleUseGuid : IId +{ + [Key] + public long Id { get; set; } + + [Required] + public long UserId { get; set; } + + [Required] + public Guid Guid { get; set; } + + [Required] + public DateTimeOffset Expires { get; set; } + + [ForeignKey(nameof(UserId))] + public virtual User User { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/SsoProvider.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/SsoProvider.cs new file mode 100644 index 0000000..481f62b --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/SsoProvider.cs @@ -0,0 +1,52 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.UserManager; + +[DisplayName("Sso Provider")] +[Table("SsoProviders", Schema = "UserManager")] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class SsoProvider : IGeneralId +{ + [Key] + public long Id { get; set; } + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [RedactAudit] + [Required] + public string ClientId { get; set; } = string.Empty; + + [RedactAudit] + [Required] + public string ClientSecret { get; set; } = string.Empty; + + [Required] + public string ValidIssuer { get; set; } = string.Empty; + + [Required] + public string AuthorizationEndpoint { get; set; } = string.Empty; + + [Required] + public string TokenEndpoint { get; set; } = string.Empty; + + [Required] + public bool IsPublic { get; set; } = true; + + [AuditSoftDelete(true)] + [Required] + public bool Deleted { get; set; } = false; + + public Guid Guid { get; set; } = Guid.NewGuid(); + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/User.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/User.cs new file mode 100644 index 0000000..701e415 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/UserManager/User.cs @@ -0,0 +1,108 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using e_suite.Nuget.PasswordHasher; +using eSuite.Core.MailService; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.UserManager; + +[DisplayName("User")] +[Table("Users", Schema = "UserManager")] +[Index(nameof(Email), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class User : IPassword, IEmailAddress, IGeneralId +{ + [Key] + public long Id { get; set; } + + [Required] + [DefaultValue("")] + public string FirstName { get; set; } = string.Empty; + + [Required] + [DefaultValue("")] + public string LastName { get; set; } = string.Empty; + + [Required] + [DefaultValue("")] + public string MiddleNames { get; set; } = string.Empty; + + [AuditName] + [NotMapped] + public string DisplayName => ((FirstName.Trim() + " " + MiddleNames).Trim() + " " + LastName).Trim(); + + [Required] + public string Email { get; set; } = string.Empty; + + [RedactAudit] + [Required] + public string Password { get; set; } = string.Empty; + + [Required] + public bool EmailConfirmed { get; set; } + + [Required] + public bool UsingTwoFactorAuthentication { get; set; } + + [RedactAudit] + [Required] + public string TwoFactorAuthenticationKey { get; set; } = string.Empty; + + [Required] + public DateTimeOffset Created { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + [AuditSoftDelete(false)] + [Required] + [DefaultValue(true)] + public bool Active { get; set; } = true; + + [Required] + [DefaultValue(1)] + public long DomainId { get; set; } + + [ForeignKey(nameof(DomainId))] + public virtual Domain.Domain Domain { get; set; } = null!; + + [DefaultValue(null)] + public long? SsoProviderId { get; set; } = null!; + + [RedactAudit] + [Required] + [DefaultValue("")] + public string SsoSubject { get; set; } = string.Empty; + + [AuditParent] + [ForeignKey(nameof(SsoProviderId))] + public virtual SsoProvider? SsoProvider { get; set; } = null!; + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData(new User + { + Id = 1, + FirstName = "Test1", + MiddleNames = string.Empty, + LastName = "User", + Active = true, + Email = "testuser1@sun-strategy.com", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + EmailConfirmed = true, + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + Created = new DateTimeOffset(2022, 06, 09, 12, 00, 00, TimeSpan.Zero), + LastUpdated = new DateTimeOffset(2022, 06, 09, 12, 00, 00, TimeSpan.Zero), + DomainId = 1, + SsoProviderId = null, + SsoSubject = string.Empty, + Guid = new Guid("{30cfcd5b-3385-43f1-b59a-fd35236f3d92}") + }); + } + + public Guid Guid { get; set; } = Guid.NewGuid(); +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/IWorkflowManager.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/IWorkflowManager.cs new file mode 100644 index 0000000..42d938f --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/IWorkflowManager.cs @@ -0,0 +1,10 @@ +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Workflow; + +public interface IWorkflowManager : IDatabaseCore +{ + DbSet Workflows { get; set; } + DbSet WorkflowVersions { get; set; } + +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/Workflow.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/Workflow.cs new file mode 100644 index 0000000..b6e66d7 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/Workflow.cs @@ -0,0 +1,33 @@ +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace e_suite.Database.Core.Tables.Workflow; + +[DisplayName("Workflow")] +[Table("Workflows", Schema = "Workflow")] +[Index(nameof(Name), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class Workflow : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } + + [AuditName] + [Required] + public string Name { get; set; } = string.Empty; + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/WorkflowVersion.cs b/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/WorkflowVersion.cs new file mode 100644 index 0000000..5bb6a60 --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/Tables/Workflow/WorkflowVersion.cs @@ -0,0 +1,72 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; +using e_suite.Database.Audit.Attributes; +using e_suite.Database.Core.Models; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Database.Core.Tables.Workflow; + +[DisplayName("Workflow Version")] +[Table("WorkflowVersions", Schema = "Workflow")] +[Index(nameof(WorkflowId), nameof(Version), IsUnique = true)] +[Index(nameof(Guid), IsUnique = true)] +public class WorkflowVersion : IGeneralId, ISoftDeletable +{ + [Key] + public long Id { get; set; } + + [Required] + public Guid Guid { get; set; } + + public long WorkflowId { get; set; } + + [Required] + public long Version { get; set; } = 0; + + [Required] + public long DomainId { get; set; } + + [AuditName] + [Required] + public string ActivityNameTemplate { get; set; } = string.Empty; + + [Required] + public string Description { get; set; } = string.Empty; + + public List Tasks { get; set; } = new(); + + [AuditSoftDelete(true)] + [Required] + [DefaultValue(false)] + public bool Deleted { get; set; } + + [AuditParent] + [ForeignKey(nameof(DomainId))] + public virtual Domain.Domain Domain { get; set; } = null!; + + [AuditParent] + [ForeignKey(nameof(WorkflowId))] + public virtual Workflow Workflow { get; set; } = null!; + + [AuditLastUpdated] + public DateTimeOffset LastUpdated { get; set; } + + private static readonly JsonSerializerOptions JsonOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = false + }; + + + public static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property(w => w.Tasks) + .HasConversion( + v => JsonSerializer.Serialize(v, JsonOptions), + v => JsonSerializer.Deserialize>(v, JsonOptions) + ); + } +} \ No newline at end of file diff --git a/e-suite.Database.Core/e-suite.Database.Core/e-suite.Database.Core.csproj b/e-suite.Database.Core/e-suite.Database.Core/e-suite.Database.Core.csproj new file mode 100644 index 0000000..c6e76bb --- /dev/null +++ b/e-suite.Database.Core/e-suite.Database.Core/e-suite.Database.Core.csproj @@ -0,0 +1,16 @@ + + + + net10.0 + e_suite.Database.Core + enable + enable + + + + + + + + + diff --git a/e-suite.Database.Core/nuget.config b/e-suite.Database.Core/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Database.Core/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Database.SqlServer/.gitattributes b/e-suite.Database.SqlServer/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Database.SqlServer/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Database.SqlServer/.gitignore b/e-suite.Database.SqlServer/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Database.SqlServer/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Database.SqlServer/.runsettings b/e-suite.Database.SqlServer/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Database.SqlServer/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Database.SqlServer/CreateDatabase.sql b/e-suite.Database.SqlServer/CreateDatabase.sql new file mode 100644 index 0000000..ffc6121 --- /dev/null +++ b/e-suite.Database.SqlServer/CreateDatabase.sql @@ -0,0 +1,18 @@ +USE [master] +GO + +CREATE DATABASE esuite + CONTAINMENT = PARTIAL + ON PRIMARY +( NAME = N'esuite', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\esuite_Primary.mdf' , SIZE = 10MB , MAXSIZE = UNLIMITED, FILEGROWTH = 10MB ) + LOG ON +( NAME = N'esuite_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\esuite_Primary.ldf' , SIZE = 1024KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB) +GO + +ALTER DATABASE esuite SET RECOVERY SIMPLE + +use esuite; +go + +CREATE USER [ApplicationUser] WITH PASSWORD=N'Plz change me on live, thank you', DEFAULT_SCHEMA=[dbo] +GO diff --git a/e-suite.Database.SqlServer/README.md b/e-suite.Database.SqlServer/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Database.SqlServer/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Database.SqlServer/azure-pipelines.yml b/e-suite.Database.SqlServer/azure-pipelines.yml new file mode 100644 index 0000000..ff386a8 --- /dev/null +++ b/e-suite.Database.SqlServer/azure-pipelines.yml @@ -0,0 +1,137 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Database.SqlServer/e-suite.Database.SqlServer.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +#This solution contains automatically generated code, with a few exceptions. Manual testing takes place to ensure code quality. +#- task: BuildQualityChecks@9 +# displayName: 'Check build quality' +# inputs: +# # ===== Warnings Policy Inputs ===== +# checkWarnings: true # Optional +# warningFailOption: fixed # Optional; Valid values: build, fixed +# warningThreshold: '0' # Optional +# #forceFewerWarnings: false # Optional +# #allowWarningVariance: false # Optional +# #warningVariance: # Required if allowWarningVariance = true +# #showStatistics: false # Optional +# #evaluateTaskWarnings: true # Optional +# #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) +# #warningSelectors: # Optional (alias: warningFilters) +# #inclusiveSelection: false # Optional (alias: inclusiveFiltering) +# #evaluateFileWarnings: false # Optional +# #warningFilesFolder: # Optional +# #warningFiles: # Required if evaluateFileWarnings = true +# #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) +# #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) +# # ===== Code Coverage Policy Inputs ===== +# checkCoverage: true # Optional +# coverageFailOption: fixed # Optional; Valid values: build, fixed +# coverageType: lines # Optional; Valid values: blocks, lines, branches, custom +# #customCoverageType: # Required if coverageType = custom +# #treat0of0as100: false # Optional +# coverageThreshold: '80' # Optional +# forceCoverageImprovement: true # Optional +# #coverageUpperThreshold: '80' # Optional +# #ignoreDecreaseAboveUpperThreshold: true # Optional +# #useUncoveredElements: false # Optional +# #allowCoverageVariance: false # Optional +# #coverageVariance: # Required if allowCoverageVariance = true +# #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage +# #coveragePrecision: '4' # Optional +# #buildConfiguration: # Optional +# #buildPlatform: # Optional +# #explicitSelector: false # Optional (alias: explicitFilter) +# # ===== Baseline Inputs ===== +# #includePartiallySucceeded: true # Optional +# #fallbackOnPRTargetBranch: true # Optional +# #baseDefinitionSelector: # Ignored - only used by UI editor +# #baseDefinitionId: # Optional +# #baseRepoId: # Ignored - only used by UI editor +# #baseBranchRef: # Optional +# # ===== Reporting Inputs ===== +# #runTitle: # Optional +# #fileAnalysisTitle: # Optional +# # ===== Advanced Inputs ===== +# #disableCertCheck: false # Optional +# #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Database.SqlServer/azurepipelines-coverage.yml b/e-suite.Database.SqlServer/azurepipelines-coverage.yml new file mode 100644 index 0000000..7a02197 --- /dev/null +++ b/e-suite.Database.SqlServer/azurepipelines-coverage.yml @@ -0,0 +1,2 @@ +coverage: + status: off \ No newline at end of file diff --git a/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/DependencyInjection/CoreRegistrationModule.cs b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/DependencyInjection/CoreRegistrationModule.cs new file mode 100644 index 0000000..ac5ce26 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/DependencyInjection/CoreRegistrationModule.cs @@ -0,0 +1,22 @@ +using Autofac; +using e_suite.Database.Core; +using e_suite.Database.SqlServer; +using eSuite.Core.Clock; + +namespace eSuite.API.DependencyInjection; + +/// +/// Used as a the primary location for IOC type registration for e-suite. +/// +internal class CoreRegistrationModule : Module +{ + /// + /// Use the builder to register all the types and interfaces that the API requires to operate properly. + /// + /// + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().SingleInstance(); + } +} \ No newline at end of file diff --git a/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/Program.cs b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/Program.cs new file mode 100644 index 0000000..c42ec78 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/Program.cs @@ -0,0 +1,30 @@ +using Autofac; +using Autofac.Extensions.DependencyInjection; +using e_suite.Database.SqlServer; +using eSuite.API.DependencyInjection; + +var builder = WebApplication.CreateBuilder(args); + + +builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureContainer(builder => + { + builder.RegisterModule(new CoreRegistrationModule()); + }); + +// Add services to the container. + +builder.AddDatabaseContext(); + +builder.Services.AddControllers(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/Properties/launchSettings.json b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/Properties/launchSettings.json new file mode 100644 index 0000000..0e1b219 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:40226", + "sslPort": 44360 + } + }, + "profiles": { + "e_suite.Database.MigrationBuilder": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7182;http://localhost:5182", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/appsettings.Development.json b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/appsettings.Development.json new file mode 100644 index 0000000..575e076 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "connectionStrings": { + "database": "Server=(local);Database=esuite;MultipleActiveResultSets=true;User ID=esuiteApplicationUser;Password=Plz change me on live, thank you;Encrypt=true;TrustServerCertificate=true;" + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/appsettings.json b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/e-suite.Database.MigrationBuilder.csproj b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/e-suite.Database.MigrationBuilder.csproj new file mode 100644 index 0000000..3ec7e39 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.MigrationBuilder/e-suite.Database.MigrationBuilder.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + enable + enable + e_suite.Database.MigrationBuilder + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer.UnitTests/ESuiteDatabaseExtensionUnitTests.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer.UnitTests/ESuiteDatabaseExtensionUnitTests.cs new file mode 100644 index 0000000..48aefcc --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer.UnitTests/ESuiteDatabaseExtensionUnitTests.cs @@ -0,0 +1,121 @@ +using e_suite.UnitTestCore; +using NUnit.Framework; + +namespace e_suite.Database.SqlServer.UnitTests; + +[TestFixture] +public class ESuiteDatabaseExtensionUnitTests : TestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [TearDown] + public void TearDown() + { + Environment.SetEnvironmentVariable("SQL_SERVER", null); + Environment.SetEnvironmentVariable("SQL_DATABASE", null); + Environment.SetEnvironmentVariable("SQL_USER", null); + Environment.SetEnvironmentVariable("SQL_PASSWORD", null); + Environment.SetEnvironmentVariable("SQL_ENCRYPT", null); + Environment.SetEnvironmentVariable("SQL_TRUSTSERVERCERTIFIATE", null); + } + + [Test] + public void ESuiteDatabaseExtension_BuildingConnectionString_ReturnsExpectedConnectionString() + { + //Arrange + const string expectedConnectionString = "Data Source=(local);Initial Catalog=esuite;Integrated Security=True;Multiple Active Result Sets=True;Encrypt=True;Trust Server Certificate=True;Application Name=e-suite"; + + //Act + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(_configuration); + + //Assert + Assert.That(connectionString, Is.EqualTo(expectedConnectionString)); + } + + [Test] + public void ESuiteDatabaseExtension_ServerNameSetInEnvironment_ReturnsExpectedConnectionString() + { + //Arrange + const string serverName = "TestServer"; + Environment.SetEnvironmentVariable("SQL_SERVER",serverName); + + var expectedConnectionString = $"Data Source={serverName};Initial Catalog=esuite;Integrated Security=True;Multiple Active Result Sets=True;Encrypt=True;Trust Server Certificate=True;Application Name=e-suite"; + + //Act + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(_configuration); + + //Assert + Assert.That(connectionString, Is.EqualTo(expectedConnectionString)); + } + + [Test] + public void ESuiteDatabaseExtension_DatabaseNameSetInEnvironment_ReturnsExpectedConnectionString() + { + //Arrange + const string databaseName = "NewDatabase"; + Environment.SetEnvironmentVariable("SQL_DATABASE", databaseName); + + var expectedConnectionString = $"Data Source=(local);Initial Catalog={databaseName};Integrated Security=True;Multiple Active Result Sets=True;Encrypt=True;Trust Server Certificate=True;Application Name=e-suite"; + + //Act + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(_configuration); + + //Assert + Assert.That(connectionString, Is.EqualTo(expectedConnectionString)); + } + + [Test] + public void ESuiteDatabaseExtension_UserNameAndPasswordSetInEnvironment_ReturnsExpectedConnectionString() + { + //Arrange + const string userName = "Testy_McTester"; + const string password = "iu435g65£&^lih45[02387y"; + Environment.SetEnvironmentVariable("SQL_USER", userName); + Environment.SetEnvironmentVariable("SQL_PASSWORD", password); + + var expectedConnectionString = $"Data Source=(local);Initial Catalog=esuite;User ID={userName};Password={password};Multiple Active Result Sets=True;Encrypt=True;Trust Server Certificate=True;Application Name=e-suite"; + + //Act + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(_configuration); + + //Assert + Assert.That(connectionString, Is.EqualTo(expectedConnectionString)); + } + + [Test] + public void ESuiteDatabaseExtension_SqlEncryptSetInEnvironment_ReturnsExpectedConnectionString() + { + //Arrange + const bool sqlEncrypt = false; + Environment.SetEnvironmentVariable("SQL_ENCRYPT", sqlEncrypt.ToString()); + + var expectedConnectionString = + $"Data Source=(local);Initial Catalog=esuite;Integrated Security=True;Multiple Active Result Sets=True;Encrypt={sqlEncrypt};Trust Server Certificate=True;Application Name=e-suite"; + + //Act + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(_configuration); + + //Assert + Assert.That(connectionString, Is.EqualTo(expectedConnectionString)); + } + + [Test] + public void ESuiteDatabaseExtension_TrustServerCertificateSetInEnvironment_ReturnsExpectedConnectionString() + { + //Arrange + const bool sqlTrustCertificate = false; + Environment.SetEnvironmentVariable("SQL_TRUSTSERVERCERTIFIATE", sqlTrustCertificate.ToString()); + + var expectedConnectionString = $"Data Source=(local);Initial Catalog=esuite;Integrated Security=True;Multiple Active Result Sets=True;Encrypt=True;Trust Server Certificate={sqlTrustCertificate};Application Name=e-suite"; + + //Act + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(_configuration); + + //Assert + Assert.That(connectionString, Is.EqualTo(expectedConnectionString)); + } +} \ No newline at end of file diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer.UnitTests/e-suite.Database.SqlServer.UnitTests.csproj b/e-suite.Database.SqlServer/e-suite.Database.SqlServer.UnitTests/e-suite.Database.SqlServer.UnitTests.csproj new file mode 100644 index 0000000..56a3c2a --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer.UnitTests/e-suite.Database.SqlServer.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + e_suite.Database.SqlServer.UnitTests + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer.sln b/e-suite.Database.SqlServer/e-suite.Database.SqlServer.sln new file mode 100644 index 0000000..1a9e36c --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer.sln @@ -0,0 +1,45 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.SqlServer", "e-suite.Database.SqlServer\e-suite.Database.SqlServer.csproj", "{5F7C8EA0-5965-4DD1-A38B-D3E24AEB1101}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.MigrationBuilder", "e-suite.Database.MigrationBuilder\e-suite.Database.MigrationBuilder.csproj", "{D4C54DE6-25BA-43BB-AD2E-E726BE97A38A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{352C481A-C1EA-42D3-B50D-11C68859816E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{5C8EF0F6-FC01-49A0-BF2C-6E47402CEEEA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Database.SqlServer.UnitTests", "e-suite.Database.SqlServer.UnitTests\e-suite.Database.SqlServer.UnitTests.csproj", "{F7139C54-59B1-4C82-9000-60437A2A2FE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5F7C8EA0-5965-4DD1-A38B-D3E24AEB1101}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F7C8EA0-5965-4DD1-A38B-D3E24AEB1101}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F7C8EA0-5965-4DD1-A38B-D3E24AEB1101}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F7C8EA0-5965-4DD1-A38B-D3E24AEB1101}.Release|Any CPU.Build.0 = Release|Any CPU + {D4C54DE6-25BA-43BB-AD2E-E726BE97A38A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4C54DE6-25BA-43BB-AD2E-E726BE97A38A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4C54DE6-25BA-43BB-AD2E-E726BE97A38A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4C54DE6-25BA-43BB-AD2E-E726BE97A38A}.Release|Any CPU.Build.0 = Release|Any CPU + {F7139C54-59B1-4C82-9000-60437A2A2FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7139C54-59B1-4C82-9000-60437A2A2FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7139C54-59B1-4C82-9000-60437A2A2FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7139C54-59B1-4C82-9000-60437A2A2FE0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {5C8EF0F6-FC01-49A0-BF2C-6E47402CEEEA} = {352C481A-C1EA-42D3-B50D-11C68859816E} + {F7139C54-59B1-4C82-9000-60437A2A2FE0} = {5C8EF0F6-FC01-49A0-BF2C-6E47402CEEEA} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A758CFBB-3337-4EAB-98AE-47F3C34559EA} + EndGlobalSection +EndGlobal diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/DatabaseNameReplacerSqlGenerator.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/DatabaseNameReplacerSqlGenerator.cs new file mode 100644 index 0000000..a6ba1b8 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/DatabaseNameReplacerSqlGenerator.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Update; + +namespace e_suite.Database.SqlServer; + +public class DatabaseNameReplacerSqlGenerator : SqlServerMigrationsSqlGenerator +{ + public DatabaseNameReplacerSqlGenerator( + MigrationsSqlGeneratorDependencies dependencies, + ICommandBatchPreparer commandBatchPreparer + ) + : base(dependencies, commandBatchPreparer) + { + } + + protected override void Generate( + MigrationOperation operation, + IModel? model, + MigrationCommandListBuilder builder) + { + if (operation is SqlOperation sqlOperation) + { + var dbName = this.Dependencies.CurrentContext.Context.Database.GetDbConnection().Database; + sqlOperation.Sql = sqlOperation.Sql.Replace("[DatabaseNameToReplace]", dbName); + } + + base.Generate(operation, model, builder); + } +} \ No newline at end of file diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/ESuiteDatabaseExtension.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/ESuiteDatabaseExtension.cs new file mode 100644 index 0000000..4956cff --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/ESuiteDatabaseExtension.cs @@ -0,0 +1,97 @@ +using e_suite.Database.Core; +using eSuite.Core.Clock; +using Microsoft.AspNetCore.Builder; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace e_suite.Database.SqlServer; + +public static class ESuiteDatabaseExtension +{ + public static void AddDatabaseContext(this WebApplicationBuilder builder) + { + var connectionString = BuildConnectionString(builder.Configuration); + + builder.Services.AddDbContext(options => options + .UseSqlServer(connectionString, b => b + .MigrationsAssembly("e-suite.Database.SqlServer") + .UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)) + ); + builder.Services.AddScoped(provider => provider.GetRequiredService()); + } + + public static Task CreateDatabase(IClock clock) + { + var configuration = BuildConfiguration(); + + var connectionString = BuildConnectionString(configuration); + + var options = new DbContextOptionsBuilder() + .UseSqlServer(connectionString) + .Options; + + var esuiteDatabase = new SqlEsuiteDatabaseDbContext(options, clock); + + return Task.FromResult(esuiteDatabase); + } + + public static IConfiguration BuildConfiguration() + { + var environmentName = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); + + var configurationBuilder = new ConfigurationBuilder() + .AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), $"appsettings.json"), true, true); + + if (!string.IsNullOrEmpty(environmentName)) + configurationBuilder = configurationBuilder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), + $"appsettings.{environmentName}.json")); + + var configuration = configurationBuilder.Build(); + return configuration; + } + +#pragma warning disable IDE0060 // Remove unused parameter + public static bool IsAzure(IConfiguration configuration) +#pragma warning restore IDE0060 // Remove unused parameter + { + var azureEnv = Environment.GetEnvironmentVariable("AZURE"); + return !string.IsNullOrWhiteSpace(azureEnv); + } + + public static string BuildConnectionString(IConfiguration configuration) + { + var builder = new SqlConnectionStringBuilder + { + ApplicationName = "e-suite", + MultipleActiveResultSets = true + }; + + var envSqlServername = Environment.GetEnvironmentVariable("SQL_SERVER"); + var envSqlDatabase = Environment.GetEnvironmentVariable("SQL_DATABASE"); + var envSqlUser = Environment.GetEnvironmentVariable("SQL_USER"); + var envSqlPassword = Environment.GetEnvironmentVariable("SQL_PASSWORD"); + var envSqlEncrypt = Environment.GetEnvironmentVariable("SQL_ENCRYPT"); + var envSqlTrustServerCertifiate = Environment.GetEnvironmentVariable("SQL_TRUSTSERVERCERTIFIATE"); + + builder.InitialCatalog = !string.IsNullOrWhiteSpace(envSqlDatabase) ? envSqlDatabase : configuration.GetValue("database:databaseName", "esuite"); + builder.DataSource = !string.IsNullOrWhiteSpace(envSqlServername) ? envSqlServername : configuration.GetValue("database:server", "(local)"); + builder.Encrypt = (!string.IsNullOrWhiteSpace(envSqlEncrypt) ? envSqlEncrypt : configuration.GetValue("database:encrypt", "true")) == "true"; + builder.TrustServerCertificate = (!string.IsNullOrWhiteSpace(envSqlTrustServerCertifiate) ? envSqlTrustServerCertifiate == "true" : configuration.GetValue("database:trustServerCertificate", true)); + var username = !string.IsNullOrWhiteSpace(envSqlUser) ? envSqlUser : configuration.GetValue("database:username", string.Empty); + var password = !string.IsNullOrWhiteSpace(envSqlPassword) ? envSqlPassword : configuration.GetValue("database:password", string.Empty); + + if (string.IsNullOrWhiteSpace(username)) + { + builder.IntegratedSecurity = true; + } + else + { + builder.UserID = username; + builder.Password = password; + } + + return builder.ToString(); + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/GlobalSuppressions.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20220823111110_Initial Database.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20220823111110_Initial Database.Designer.cs new file mode 100644 index 0000000..b1dba99 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20220823111110_Initial Database.Designer.cs @@ -0,0 +1,280 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace e_suite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20220823111110_Initial Database")] + partial class InitialDatabase + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Core.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Core.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20220823111110_Initial Database.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20220823111110_Initial Database.cs new file mode 100644 index 0000000..c1d379c --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20220823111110_Initial Database.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace e_suite.Database.SqlServer.Migrations +{ + public partial class InitialDatabase : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + var configuration = ESuiteDatabaseExtension.BuildConfiguration(); + if (!ESuiteDatabaseExtension.IsAzure(configuration)) + { + migrationBuilder.Sql("sp_configure 'contained database authentication', 1;", true); + migrationBuilder.Sql("RECONFIGURE", true); + + migrationBuilder.Sql("ALTER DATABASE [[DatabaseNameToReplace]] SET RECOVERY SIMPLE", true); + migrationBuilder.Sql("ALTER DATABASE [[DatabaseNameToReplace]] SET CONTAINMENT = PARTIAL WITH NO_WAIT", true); + } + + migrationBuilder.Sql("CREATE USER [[DatabaseNameToReplace]ApplicationUser] WITH PASSWORD=N'Plz change me on live, thank you', DEFAULT_SCHEMA=[dbo]"); + migrationBuilder.Sql("ALTER ROLE[db_datareader] ADD MEMBER [[DatabaseNameToReplace]ApplicationUser]"); + migrationBuilder.Sql("ALTER ROLE[db_datawriter] ADD MEMBER [[DatabaseNameToReplace]ApplicationUser]"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20221212150403_Initial table structure.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20221212150403_Initial table structure.Designer.cs new file mode 100644 index 0000000..bce9d0e --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20221212150403_Initial table structure.Designer.cs @@ -0,0 +1,1184 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20221212150403_Initial table structure")] + partial class Initialtablestructure + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("OrganisationId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("SiteId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20221212150403_Initial table structure.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20221212150403_Initial table structure.cs new file mode 100644 index 0000000..4d20714 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20221212150403_Initial table structure.cs @@ -0,0 +1,1112 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class Initialtablestructure : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "Audit"); + + migrationBuilder.EnsureSchema( + name: "Contacts"); + + migrationBuilder.EnsureSchema( + name: "CustomFields"); + + migrationBuilder.EnsureSchema( + name: "UserManager"); + + migrationBuilder.EnsureSchema( + name: "Sentinel"); + + migrationBuilder.EnsureSchema( + name: "Forms"); + + migrationBuilder.EnsureSchema( + name: "Glossaries"); + + migrationBuilder.EnsureSchema( + name: "Printer"); + + migrationBuilder.EnsureSchema( + name: "Diagnostics"); + + migrationBuilder.EnsureSchema( + name: "Sequences"); + + migrationBuilder.CreateTable( + name: "AuditDetails", + schema: "Audit", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "bigint", nullable: false), + UserDisplayName = table.Column(type: "nvarchar(max)", nullable: false), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + DateTime = table.Column(type: "datetimeoffset", nullable: false), + Fields = table.Column(type: "nvarchar(max)", nullable: false), + Comment = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditDetails", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Contacts", + schema: "Contacts", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + JCard = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Contacts", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CustomFields", + schema: "CustomFields", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + FieldType = table.Column(type: "int", nullable: false), + MinEntries = table.Column(type: "bigint", nullable: false), + MaxEntries = table.Column(type: "bigint", nullable: true), + DefaultValue = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomFields", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "FailedAccessAttempts", + schema: "Sentinel", + columns: table => new + { + IPAddress = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + AttemptedTime = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FailedAccessAttempts", x => new { x.IPAddress, x.AttemptedTime }); + }); + + migrationBuilder.CreateTable( + name: "FormTemplates", + schema: "Forms", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FormTemplates", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Glossaries", + schema: "Glossaries", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ParentId = table.Column(type: "bigint", nullable: true), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Glossaries", x => x.Id); + table.ForeignKey( + name: "FK_Glossaries_Glossaries_ParentId", + column: x => x.ParentId, + principalSchema: "Glossaries", + principalTable: "Glossaries", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "Organisations", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false), + Address = table.Column(type: "nvarchar(max)", nullable: false), + Status = table.Column(type: "int", nullable: false), + Deleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Organisations", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "PerformanceReports", + schema: "Diagnostics", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Host = table.Column(type: "nvarchar(max)", nullable: false), + ControllerName = table.Column(type: "nvarchar(max)", nullable: false), + ActionName = table.Column(type: "nvarchar(max)", nullable: false), + RequestType = table.Column(type: "nvarchar(max)", nullable: false), + ActionParameters = table.Column(type: "nvarchar(max)", nullable: false), + StartDateTime = table.Column(type: "datetimeoffset", nullable: false), + Timings = table.Column(type: "nvarchar(max)", nullable: false), + TotalTimeMS = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PerformanceReports", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "PerformanceThresholds", + schema: "Diagnostics", + columns: table => new + { + ControllerName = table.Column(type: "nvarchar(450)", nullable: false), + ActionName = table.Column(type: "nvarchar(450)", nullable: false), + RequestType = table.Column(type: "nvarchar(450)", nullable: false), + TotalTimeMS = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PerformanceThresholds", x => new { x.ControllerName, x.ActionName, x.RequestType }); + }); + + migrationBuilder.CreateTable( + name: "Sequences", + schema: "Sequences", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Rollover = table.Column(type: "int", nullable: false), + Pattern = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + Seed = table.Column(type: "bigint", nullable: false), + Increment = table.Column(type: "bigint", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + LastIssueDate = table.Column(type: "datetimeoffset", nullable: true), + LastIssueValue = table.Column(type: "bigint", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Sequences", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + schema: "UserManager", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FirstName = table.Column(type: "nvarchar(max)", nullable: false), + LastName = table.Column(type: "nvarchar(max)", nullable: false), + MiddleNames = table.Column(type: "nvarchar(max)", nullable: false), + Email = table.Column(type: "nvarchar(450)", nullable: false), + Password = table.Column(type: "nvarchar(max)", nullable: false), + EmailConfirmed = table.Column(type: "bit", nullable: false), + UsingTwoFactorAuthentication = table.Column(type: "bit", nullable: false), + TwoFactorAuthenticationKey = table.Column(type: "nvarchar(max)", nullable: false), + Created = table.Column(type: "datetimeoffset", nullable: false), + LastUpdated = table.Column(type: "datetimeoffset", nullable: false), + Active = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AuditEntries", + schema: "Audit", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + AuditLogId = table.Column(type: "bigint", nullable: false), + EntityName = table.Column(type: "nvarchar(max)", nullable: false), + PrimaryKey = table.Column(type: "nvarchar(max)", nullable: false), + DisplayName = table.Column(type: "nvarchar(max)", nullable: false), + IsPrimary = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditEntries", x => x.Id); + table.ForeignKey( + name: "FK_AuditEntries_AuditDetails_AuditLogId", + column: x => x.AuditLogId, + principalSchema: "Audit", + principalTable: "AuditDetails", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CustomFieldFormTemplates", + schema: "CustomFields", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomFieldId = table.Column(type: "bigint", nullable: false), + FormTemplateId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomFieldFormTemplates", x => x.Id); + table.ForeignKey( + name: "FK_CustomFieldFormTemplates_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CustomFieldFormTemplates_FormTemplates_FormTemplateId", + column: x => x.FormTemplateId, + principalSchema: "Forms", + principalTable: "FormTemplates", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "FormTemplateVersions", + schema: "Forms", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + TemplateId = table.Column(type: "bigint", nullable: false), + Version = table.Column(type: "bigint", nullable: false), + FormDefinition = table.Column(type: "nvarchar(max)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FormTemplateVersions", x => x.Id); + table.ForeignKey( + name: "FK_FormTemplateVersions_FormTemplates_TemplateId", + column: x => x.TemplateId, + principalSchema: "Forms", + principalTable: "FormTemplates", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CustomFieldGlossaries", + schema: "CustomFields", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomFieldId = table.Column(type: "bigint", nullable: false), + GlossaryId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomFieldGlossaries", x => x.Id); + table.ForeignKey( + name: "FK_CustomFieldGlossaries_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CustomFieldGlossaries_Glossaries_GlossaryId", + column: x => x.GlossaryId, + principalSchema: "Glossaries", + principalTable: "Glossaries", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "GlossaryCustomFields", + schema: "Glossaries", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + GlossaryId = table.Column(type: "bigint", nullable: false), + CustomFieldId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GlossaryCustomFields", x => x.Id); + table.UniqueConstraint("AK_GlossaryCustomFields_GlossaryId_CustomFieldId", x => new { x.GlossaryId, x.CustomFieldId }); + table.ForeignKey( + name: "FK_GlossaryCustomFields_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_GlossaryCustomFields_Glossaries_GlossaryId", + column: x => x.GlossaryId, + principalSchema: "Glossaries", + principalTable: "Glossaries", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "GlossaryCustomFieldValues", + schema: "Glossaries", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + GlossaryId = table.Column(type: "bigint", nullable: false), + CustomFieldId = table.Column(type: "bigint", nullable: false), + Index = table.Column(type: "bigint", nullable: false), + Value = table.Column(type: "nvarchar(max)", nullable: false), + DisplayValue = table.Column(type: "nvarchar(max)", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GlossaryCustomFieldValues", x => x.Id); + table.UniqueConstraint("AK_GlossaryCustomFieldValues_GlossaryId_CustomFieldId_Index", x => new { x.GlossaryId, x.CustomFieldId, x.Index }); + table.ForeignKey( + name: "FK_GlossaryCustomFieldValues_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_GlossaryCustomFieldValues_Glossaries_GlossaryId", + column: x => x.GlossaryId, + principalSchema: "Glossaries", + principalTable: "Glossaries", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OrganisationContacts", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + OrganisationId = table.Column(type: "bigint", nullable: false), + ContactId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrganisationContacts", x => x.Id); + table.ForeignKey( + name: "FK_OrganisationContacts_Contacts_ContactId", + column: x => x.ContactId, + principalSchema: "Contacts", + principalTable: "Contacts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_OrganisationContacts_Organisations_OrganisationId", + column: x => x.OrganisationId, + principalSchema: "Printer", + principalTable: "Organisations", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Sites", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false), + Address = table.Column(type: "nvarchar(max)", nullable: false), + Status = table.Column(type: "int", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + OrganisationId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Sites", x => x.Id); + table.ForeignKey( + name: "FK_Sites_Organisations_OrganisationId", + column: x => x.OrganisationId, + principalSchema: "Printer", + principalTable: "Organisations", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CustomFieldSequences", + schema: "CustomFields", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomFieldId = table.Column(type: "bigint", nullable: false), + SequenceId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomFieldSequences", x => x.Id); + table.ForeignKey( + name: "FK_CustomFieldSequences_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CustomFieldSequences_Sequences_SequenceId", + column: x => x.SequenceId, + principalSchema: "Sequences", + principalTable: "Sequences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "EmailUserActions", + schema: "UserManager", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "bigint", nullable: false), + EmailActionType = table.Column(type: "int", nullable: false), + Token = table.Column(type: "uniqueidentifier", nullable: false), + Created = table.Column(type: "datetimeoffset", nullable: false), + Expires = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_EmailUserActions", x => x.Id); + table.UniqueConstraint("AK_EmailUserActions_Token_EmailActionType", x => new { x.Token, x.EmailActionType }); + table.ForeignKey( + name: "FK_EmailUserActions_Users_UserId", + column: x => x.UserId, + principalSchema: "UserManager", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AuditDrillHierarchies", + schema: "Audit", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ParentAuditDrillDownEntityId = table.Column(type: "bigint", nullable: false), + ChildAuditDrillDownEntityId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditDrillHierarchies", x => x.Id); + table.ForeignKey( + name: "FK_AuditDrillHierarchies_AuditEntries_ChildAuditDrillDownEntityId", + column: x => x.ChildAuditDrillDownEntityId, + principalSchema: "Audit", + principalTable: "AuditEntries", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_AuditDrillHierarchies_AuditEntries_ParentAuditDrillDownEntityId", + column: x => x.ParentAuditDrillDownEntityId, + principalSchema: "Audit", + principalTable: "AuditEntries", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "FormInstances", + schema: "Forms", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FormTemplateVersionId = table.Column(type: "bigint", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FormInstances", x => x.Id); + table.ForeignKey( + name: "FK_FormInstances_FormTemplateVersions_FormTemplateVersionId", + column: x => x.FormTemplateVersionId, + principalSchema: "Forms", + principalTable: "FormTemplateVersions", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SiteContacts", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SiteId = table.Column(type: "bigint", nullable: false), + ContactId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SiteContacts", x => x.Id); + table.ForeignKey( + name: "FK_SiteContacts_Contacts_ContactId", + column: x => x.ContactId, + principalSchema: "Contacts", + principalTable: "Contacts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_SiteContacts_Sites_SiteId", + column: x => x.SiteId, + principalSchema: "Printer", + principalTable: "Sites", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Specifications", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false), + FormInstanceId = table.Column(type: "bigint", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + SiteId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Specifications", x => x.Id); + table.ForeignKey( + name: "FK_Specifications_Sites_SiteId", + column: x => x.SiteId, + principalSchema: "Printer", + principalTable: "Sites", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "FormFieldInstances", + schema: "Forms", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FormInstanceId = table.Column(type: "bigint", nullable: false), + CustomFieldId = table.Column(type: "bigint", nullable: false), + Index = table.Column(type: "bigint", nullable: false), + Value = table.Column(type: "nvarchar(max)", nullable: false), + DisplayValue = table.Column(type: "nvarchar(max)", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FormFieldInstances", x => x.Id); + table.ForeignKey( + name: "FK_FormFieldInstances_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_FormFieldInstances_FormInstances_FormInstanceId", + column: x => x.FormInstanceId, + principalSchema: "Forms", + principalTable: "FormInstances", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + schema: "Glossaries", + table: "Glossaries", + columns: new[] { "Id", "Deleted", "Guid", "Name", "ParentId" }, + values: new object[,] + { + { 1L, false, new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), "System", null }, + { 2L, false, new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), "Domain", null } + }); + + migrationBuilder.InsertData( + schema: "Diagnostics", + table: "PerformanceThresholds", + columns: new[] { "ActionName", "ControllerName", "RequestType", "TotalTimeMS" }, + values: new object[] { "", "", "", 2000 }); + + migrationBuilder.InsertData( + schema: "UserManager", + table: "Users", + columns: new[] { "Id", "Active", "Created", "Email", "EmailConfirmed", "FirstName", "Guid", "LastName", "LastUpdated", "MiddleNames", "Password", "TwoFactorAuthenticationKey", "UsingTwoFactorAuthentication" }, + values: new object[] { 1L, true, new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), "testuser1@sun-strategy.com", true, "Test1", new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), "User", new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), "", "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", false }); + + migrationBuilder.CreateIndex( + name: "IX_AuditDrillHierarchies_ChildAuditDrillDownEntityId", + schema: "Audit", + table: "AuditDrillHierarchies", + column: "ChildAuditDrillDownEntityId"); + + migrationBuilder.CreateIndex( + name: "IX_AuditDrillHierarchies_ParentAuditDrillDownEntityId", + schema: "Audit", + table: "AuditDrillHierarchies", + column: "ParentAuditDrillDownEntityId"); + + migrationBuilder.CreateIndex( + name: "IX_AuditEntries_AuditLogId", + schema: "Audit", + table: "AuditEntries", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_Contacts_Guid", + schema: "Contacts", + table: "Contacts", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Contacts_Id", + schema: "Contacts", + table: "Contacts", + column: "Id", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldFormTemplates_CustomFieldId", + schema: "CustomFields", + table: "CustomFieldFormTemplates", + column: "CustomFieldId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldFormTemplates_FormTemplateId", + schema: "CustomFields", + table: "CustomFieldFormTemplates", + column: "FormTemplateId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldGlossaries_CustomFieldId", + schema: "CustomFields", + table: "CustomFieldGlossaries", + column: "CustomFieldId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldGlossaries_GlossaryId", + schema: "CustomFields", + table: "CustomFieldGlossaries", + column: "GlossaryId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomFields_Guid", + schema: "CustomFields", + table: "CustomFields", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_CustomFields_Name", + schema: "CustomFields", + table: "CustomFields", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldSequences_CustomFieldId", + schema: "CustomFields", + table: "CustomFieldSequences", + column: "CustomFieldId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldSequences_SequenceId", + schema: "CustomFields", + table: "CustomFieldSequences", + column: "SequenceId"); + + migrationBuilder.CreateIndex( + name: "IX_EmailUserActions_UserId", + schema: "UserManager", + table: "EmailUserActions", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_FormFieldInstances_CustomFieldId", + schema: "Forms", + table: "FormFieldInstances", + column: "CustomFieldId"); + + migrationBuilder.CreateIndex( + name: "IX_FormFieldInstances_FormInstanceId_CustomFieldId_Index", + schema: "Forms", + table: "FormFieldInstances", + columns: new[] { "FormInstanceId", "CustomFieldId", "Index" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FormFieldInstances_Guid", + schema: "Forms", + table: "FormFieldInstances", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FormInstances_FormTemplateVersionId", + schema: "Forms", + table: "FormInstances", + column: "FormTemplateVersionId"); + + migrationBuilder.CreateIndex( + name: "IX_FormInstances_Guid", + schema: "Forms", + table: "FormInstances", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FormTemplates_Guid", + schema: "Forms", + table: "FormTemplates", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FormTemplates_Name", + schema: "Forms", + table: "FormTemplates", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FormTemplateVersions_Guid", + schema: "Forms", + table: "FormTemplateVersions", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FormTemplateVersions_TemplateId_Version", + schema: "Forms", + table: "FormTemplateVersions", + columns: new[] { "TemplateId", "Version" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Glossaries_Guid", + schema: "Glossaries", + table: "Glossaries", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Glossaries_Id_ParentId", + schema: "Glossaries", + table: "Glossaries", + columns: new[] { "Id", "ParentId" }, + unique: true, + filter: "[ParentId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_Glossaries_Name", + schema: "Glossaries", + table: "Glossaries", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Glossaries_ParentId", + schema: "Glossaries", + table: "Glossaries", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_GlossaryCustomFields_CustomFieldId", + schema: "Glossaries", + table: "GlossaryCustomFields", + column: "CustomFieldId"); + + migrationBuilder.CreateIndex( + name: "IX_GlossaryCustomFieldValues_CustomFieldId", + schema: "Glossaries", + table: "GlossaryCustomFieldValues", + column: "CustomFieldId"); + + migrationBuilder.CreateIndex( + name: "IX_GlossaryCustomFieldValues_GlossaryId_CustomFieldId_Index", + schema: "Glossaries", + table: "GlossaryCustomFieldValues", + columns: new[] { "GlossaryId", "CustomFieldId", "Index" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_GlossaryCustomFieldValues_Guid", + schema: "Glossaries", + table: "GlossaryCustomFieldValues", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_OrganisationContacts_ContactId", + schema: "Printer", + table: "OrganisationContacts", + column: "ContactId"); + + migrationBuilder.CreateIndex( + name: "IX_OrganisationContacts_OrganisationId", + schema: "Printer", + table: "OrganisationContacts", + column: "OrganisationId"); + + migrationBuilder.CreateIndex( + name: "IX_Organisations_Guid", + schema: "Printer", + table: "Organisations", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Organisations_Id", + schema: "Printer", + table: "Organisations", + column: "Id", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Sequences_Guid", + schema: "Sequences", + table: "Sequences", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Sequences_Name", + schema: "Sequences", + table: "Sequences", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_SiteContacts_ContactId", + schema: "Printer", + table: "SiteContacts", + column: "ContactId"); + + migrationBuilder.CreateIndex( + name: "IX_SiteContacts_SiteId", + schema: "Printer", + table: "SiteContacts", + column: "SiteId"); + + migrationBuilder.CreateIndex( + name: "IX_Sites_Guid", + schema: "Printer", + table: "Sites", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Sites_Id", + schema: "Printer", + table: "Sites", + column: "Id", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Sites_OrganisationId", + schema: "Printer", + table: "Sites", + column: "OrganisationId"); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_Guid", + schema: "Printer", + table: "Specifications", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_Id", + schema: "Printer", + table: "Specifications", + column: "Id", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_SiteId", + schema: "Printer", + table: "Specifications", + column: "SiteId"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Email", + schema: "UserManager", + table: "Users", + column: "Email", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Users_Guid", + schema: "UserManager", + table: "Users", + column: "Guid", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AuditDrillHierarchies", + schema: "Audit"); + + migrationBuilder.DropTable( + name: "CustomFieldFormTemplates", + schema: "CustomFields"); + + migrationBuilder.DropTable( + name: "CustomFieldGlossaries", + schema: "CustomFields"); + + migrationBuilder.DropTable( + name: "CustomFieldSequences", + schema: "CustomFields"); + + migrationBuilder.DropTable( + name: "EmailUserActions", + schema: "UserManager"); + + migrationBuilder.DropTable( + name: "FailedAccessAttempts", + schema: "Sentinel"); + + migrationBuilder.DropTable( + name: "FormFieldInstances", + schema: "Forms"); + + migrationBuilder.DropTable( + name: "GlossaryCustomFields", + schema: "Glossaries"); + + migrationBuilder.DropTable( + name: "GlossaryCustomFieldValues", + schema: "Glossaries"); + + migrationBuilder.DropTable( + name: "OrganisationContacts", + schema: "Printer"); + + migrationBuilder.DropTable( + name: "PerformanceReports", + schema: "Diagnostics"); + + migrationBuilder.DropTable( + name: "PerformanceThresholds", + schema: "Diagnostics"); + + migrationBuilder.DropTable( + name: "SiteContacts", + schema: "Printer"); + + migrationBuilder.DropTable( + name: "Specifications", + schema: "Printer"); + + migrationBuilder.DropTable( + name: "AuditEntries", + schema: "Audit"); + + migrationBuilder.DropTable( + name: "Sequences", + schema: "Sequences"); + + migrationBuilder.DropTable( + name: "Users", + schema: "UserManager"); + + migrationBuilder.DropTable( + name: "FormInstances", + schema: "Forms"); + + migrationBuilder.DropTable( + name: "CustomFields", + schema: "CustomFields"); + + migrationBuilder.DropTable( + name: "Glossaries", + schema: "Glossaries"); + + migrationBuilder.DropTable( + name: "Contacts", + schema: "Contacts"); + + migrationBuilder.DropTable( + name: "Sites", + schema: "Printer"); + + migrationBuilder.DropTable( + name: "AuditDetails", + schema: "Audit"); + + migrationBuilder.DropTable( + name: "FormTemplateVersions", + schema: "Forms"); + + migrationBuilder.DropTable( + name: "Organisations", + schema: "Printer"); + + migrationBuilder.DropTable( + name: "FormTemplates", + schema: "Forms"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230218142049_DomainAndMailTemplates.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230218142049_DomainAndMailTemplates.Designer.cs new file mode 100644 index 0000000..eecdb91 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230218142049_DomainAndMailTemplates.Designer.cs @@ -0,0 +1,1321 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230218142049_DomainAndMailTemplates")] + partial class DomainAndMailTemplates + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("OrganisationId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("SiteId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("b16f9801-5e83-4766-921d-b295b3b8db15"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230218142049_DomainAndMailTemplates.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230218142049_DomainAndMailTemplates.cs new file mode 100644 index 0000000..9e3b0be --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230218142049_DomainAndMailTemplates.cs @@ -0,0 +1,177 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class DomainAndMailTemplates : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "Domain"); + + migrationBuilder.EnsureSchema( + name: "Mail"); + + migrationBuilder.AddColumn( + name: "DomainId", + schema: "UserManager", + table: "Users", + type: "bigint", + nullable: false, + defaultValue: 1L); + + migrationBuilder.CreateTable( + name: "Domains", + schema: "Domain", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Domains", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "MailTemplates", + schema: "Mail", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + MailType = table.Column(type: "int", nullable: false), + Subject = table.Column(type: "nvarchar(max)", nullable: false), + TemplateDefinition = table.Column(type: "nvarchar(max)", nullable: false), + DomainId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MailTemplates", x => x.Id); + table.ForeignKey( + name: "FK_MailTemplates_Domains_DomainId", + column: x => x.DomainId, + principalSchema: "Domain", + principalTable: "Domains", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + schema: "Domain", + table: "Domains", + columns: new[] { "Id", "Deleted", "Guid", "Name" }, + values: new object[] { 1L, false, new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), "Sun-Strategy" }); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + columns: new[] { "DomainId", "Guid" }, + values: new object[] { 1L, new Guid("b16f9801-5e83-4766-921d-b295b3b8db15") }); + + migrationBuilder.InsertData( + schema: "Mail", + table: "MailTemplates", + columns: new[] { "Id", "Deleted", "DomainId", "Guid", "MailType", "Subject", "TemplateDefinition" }, + values: new object[,] + { + { 1L, false, 1L, new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), 0, "Confirmation e-mail", "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." }, + { 2L, false, 1L, new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), 2, "Password reset", "

Please follow the link to reset your password


Reset Password" }, + { 3L, false, 1L, new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), 1, "Disable two factor authentication", "

Please follow the link to reset two factor authentication


Disable two factor authentication" } + }); + + migrationBuilder.CreateIndex( + name: "IX_Users_DomainId", + schema: "UserManager", + table: "Users", + column: "DomainId"); + + migrationBuilder.CreateIndex( + name: "IX_Domains_Guid", + schema: "Domain", + table: "Domains", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Domains_Name", + schema: "Domain", + table: "Domains", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MailTemplates_DomainId_MailType", + schema: "Mail", + table: "MailTemplates", + columns: new[] { "DomainId", "MailType" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MailTemplates_Guid", + schema: "Mail", + table: "MailTemplates", + column: "Guid", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_Users_Domains_DomainId", + schema: "UserManager", + table: "Users", + column: "DomainId", + principalSchema: "Domain", + principalTable: "Domains", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Users_Domains_DomainId", + schema: "UserManager", + table: "Users"); + + migrationBuilder.DropTable( + name: "MailTemplates", + schema: "Mail"); + + migrationBuilder.DropTable( + name: "Domains", + schema: "Domain"); + + migrationBuilder.DropIndex( + name: "IX_Users_DomainId", + schema: "UserManager", + table: "Users"); + + migrationBuilder.DropColumn( + name: "DomainId", + schema: "UserManager", + table: "Users"); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92")); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230317163814_Roles.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230317163814_Roles.Designer.cs new file mode 100644 index 0000000..ccd3700 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230317163814_Roles.Designer.cs @@ -0,0 +1,1511 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230317163814_Roles")] + partial class Roles + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasAlternateKey("DomainId", "Name"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("OrganisationId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("SiteId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("0a30fec6-bcb8-40cb-b0af-0b5ba711c8d0"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230317163814_Roles.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230317163814_Roles.cs new file mode 100644 index 0000000..2bfa44f --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230317163814_Roles.cs @@ -0,0 +1,166 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class Roles : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Roles", + schema: "Domain", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(450)", nullable: false), + IsSuperUser = table.Column(type: "bit", nullable: false), + IsAdministrator = table.Column(type: "bit", nullable: false), + CanDelete = table.Column(type: "bit", nullable: false), + DomainId = table.Column(type: "bigint", nullable: false), + Deleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Roles", x => x.Id); + table.UniqueConstraint("AK_Roles_DomainId_Name", x => new { x.DomainId, x.Name }); + table.ForeignKey( + name: "FK_Roles_Domains_DomainId", + column: x => x.DomainId, + principalSchema: "Domain", + principalTable: "Domains", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "RoleAccess", + schema: "Domain", + columns: table => new + { + RoleId = table.Column(type: "bigint", nullable: false), + AccessKey = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RoleAccess", x => new { x.RoleId, x.AccessKey }); + table.ForeignKey( + name: "FK_RoleAccess_Roles_RoleId", + column: x => x.RoleId, + principalSchema: "Domain", + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserRoles", + schema: "Domain", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "bigint", nullable: false), + RoleId = table.Column(type: "bigint", nullable: false), + Deleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRoles", x => x.Id); + table.UniqueConstraint("AK_UserRoles_UserId_RoleId", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_UserRoles_Roles_RoleId", + column: x => x.RoleId, + principalSchema: "Domain", + principalTable: "Roles", + principalColumn: "Id", + onUpdate: ReferentialAction.NoAction, + onDelete: ReferentialAction.NoAction); + table.ForeignKey( + name: "FK_UserRoles_Users_UserId", + column: x => x.UserId, + principalSchema: "UserManager", + principalTable: "Users", + principalColumn: "Id", + onUpdate: ReferentialAction.NoAction, + onDelete: ReferentialAction.NoAction); + }); + + migrationBuilder.InsertData( + schema: "Domain", + table: "Roles", + columns: ["Id", "CanDelete", "Deleted", "DomainId", "Guid", "IsAdministrator", "IsSuperUser", "Name"], + values: new object[,] + { + { 1L, false, false, 1L, new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), false, true, "Super Users" }, + { 2L, false, false, 1L, new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), true, false, "Administrators" } + }); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("0a30fec6-bcb8-40cb-b0af-0b5ba711c8d0")); + + migrationBuilder.InsertData( + schema: "Domain", + table: "UserRoles", + columns: ["Id", "Deleted", "RoleId", "UserId"], + values: [1L, false, 1L, 1L]); + + migrationBuilder.CreateIndex( + name: "IX_Roles_Guid", + schema: "Domain", + table: "Roles", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_UserRoles_RoleId", + schema: "Domain", + table: "UserRoles", + column: "RoleId"); + + migrationBuilder.Sql( + "create or alter view Domain.UserAccess with schemabinding as\r\nselect\r\n\tur.UserId,\r\n\tra.AccessKey,\r\n\tr.DomainId\r\nfrom [Domain].[UserRoles] as ur\r\njoin UserManager.Users as u\r\n\ton u.Id = ur.UserId \r\n\tand u.Active = 1\r\njoin [Domain].[Roles] as r\r\n\ton r.Id = ur.RoleId\r\n\tand r.Deleted = 0\r\njoin [Domain].[RoleAccess] as ra\r\n\ton ra.RoleId = ur.RoleId"); + + migrationBuilder.Sql( + "create unique clustered index IX_UserAccess_UserId_AccessKey_DomainId on Domain.UserAccess( UserId, AccessKey, DomainId )"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql("drop index IX_UserAccess_UserId_RoleId_AccessKey on Domain.UserAccess"); + + migrationBuilder.Sql("drop view Domain.UserAccess"); + + migrationBuilder.DropTable( + name: "RoleAccess", + schema: "Domain"); + + migrationBuilder.DropTable( + name: "UserRoles", + schema: "Domain"); + + migrationBuilder.DropTable( + name: "Roles", + schema: "Domain"); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("b16f9801-5e83-4766-921d-b295b3b8db15")); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230327122251_ChangeRoleAlternateKey.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230327122251_ChangeRoleAlternateKey.Designer.cs new file mode 100644 index 0000000..3dfb2cb --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230327122251_ChangeRoleAlternateKey.Designer.cs @@ -0,0 +1,1512 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230327122251_ChangeRoleAlternateKey")] + partial class ChangeRoleAlternateKey + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("OrganisationId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("SiteId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("00bc6d95-2e7e-43c9-8455-d0270ca2f2d7"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230327122251_ChangeRoleAlternateKey.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230327122251_ChangeRoleAlternateKey.cs new file mode 100644 index 0000000..0dca4af --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230327122251_ChangeRoleAlternateKey.cs @@ -0,0 +1,74 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class ChangeRoleAlternateKey : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropUniqueConstraint( + name: "AK_Roles_DomainId_Name", + schema: "Domain", + table: "Roles"); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Roles", + keyColumn: "Id", + keyValue: 2L, + column: "Guid", + value: new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb")); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("00bc6d95-2e7e-43c9-8455-d0270ca2f2d7")); + + migrationBuilder.CreateIndex( + name: "IX_Roles_DomainId_Name", + schema: "Domain", + table: "Roles", + columns: new[] { "DomainId", "Name" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Roles_DomainId_Name", + schema: "Domain", + table: "Roles"); + + migrationBuilder.AddUniqueConstraint( + name: "AK_Roles_DomainId_Name", + schema: "Domain", + table: "Roles", + columns: new[] { "DomainId", "Name" }); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Roles", + keyColumn: "Id", + keyValue: 2L, + column: "Guid", + value: new Guid("32d65817-4de4-4bd5-912e-2b33054a2171")); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("0a30fec6-bcb8-40cb-b0af-0b5ba711c8d0")); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230426141604_ChangesToSitesTables.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230426141604_ChangesToSitesTables.Designer.cs new file mode 100644 index 0000000..c95aa36 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230426141604_ChangesToSitesTables.Designer.cs @@ -0,0 +1,1499 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230426141604_ChangesToSitesTables")] + partial class ChangesToSitesTables + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("9f0a5037-44a9-45cf-8025-d5ae65f5f9b9"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230426141604_ChangesToSitesTables.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230426141604_ChangesToSitesTables.cs new file mode 100644 index 0000000..177dbd2 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230426141604_ChangesToSitesTables.cs @@ -0,0 +1,167 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class ChangesToSitesTables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Sites_Id", + schema: "Printer", + table: "Sites"); + + migrationBuilder.DropPrimaryKey( + name: "PK_SiteContacts", + schema: "Printer", + table: "SiteContacts"); + + migrationBuilder.DropIndex( + name: "IX_SiteContacts_SiteId", + schema: "Printer", + table: "SiteContacts"); + + migrationBuilder.DropPrimaryKey( + name: "PK_OrganisationContacts", + schema: "Printer", + table: "OrganisationContacts"); + + migrationBuilder.DropIndex( + name: "IX_OrganisationContacts_OrganisationId", + schema: "Printer", + table: "OrganisationContacts"); + + migrationBuilder.DropColumn( + name: "Id", + schema: "Printer", + table: "SiteContacts"); + + migrationBuilder.DropColumn( + name: "Id", + schema: "Printer", + table: "OrganisationContacts"); + + migrationBuilder.AddColumn( + name: "Primary", + schema: "Printer", + table: "SiteContacts", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "Primary", + schema: "Printer", + table: "OrganisationContacts", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddPrimaryKey( + name: "PK_SiteContacts", + schema: "Printer", + table: "SiteContacts", + columns: new[] { "SiteId", "ContactId" }); + + migrationBuilder.AddPrimaryKey( + name: "PK_OrganisationContacts", + schema: "Printer", + table: "OrganisationContacts", + columns: new[] { "OrganisationId", "ContactId" }); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("9f0a5037-44a9-45cf-8025-d5ae65f5f9b9")); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_SiteContacts", + schema: "Printer", + table: "SiteContacts"); + + migrationBuilder.DropPrimaryKey( + name: "PK_OrganisationContacts", + schema: "Printer", + table: "OrganisationContacts"); + + migrationBuilder.DropColumn( + name: "Primary", + schema: "Printer", + table: "SiteContacts"); + + migrationBuilder.DropColumn( + name: "Primary", + schema: "Printer", + table: "OrganisationContacts"); + + migrationBuilder.AddColumn( + name: "Id", + schema: "Printer", + table: "SiteContacts", + type: "bigint", + nullable: false, + defaultValue: 0L) + .Annotation("SqlServer:Identity", "1, 1"); + + migrationBuilder.AddColumn( + name: "Id", + schema: "Printer", + table: "OrganisationContacts", + type: "bigint", + nullable: false, + defaultValue: 0L) + .Annotation("SqlServer:Identity", "1, 1"); + + migrationBuilder.AddPrimaryKey( + name: "PK_SiteContacts", + schema: "Printer", + table: "SiteContacts", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_OrganisationContacts", + schema: "Printer", + table: "OrganisationContacts", + column: "Id"); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("00bc6d95-2e7e-43c9-8455-d0270ca2f2d7")); + + migrationBuilder.CreateIndex( + name: "IX_Sites_Id", + schema: "Printer", + table: "Sites", + column: "Id", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_SiteContacts_SiteId", + schema: "Printer", + table: "SiteContacts", + column: "SiteId"); + + migrationBuilder.CreateIndex( + name: "IX_OrganisationContacts_OrganisationId", + schema: "Printer", + table: "OrganisationContacts", + column: "OrganisationId"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230504131610_AddedPrinterSpecificationsGlossary.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230504131610_AddedPrinterSpecificationsGlossary.Designer.cs new file mode 100644 index 0000000..63dd4f2 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230504131610_AddedPrinterSpecificationsGlossary.Designer.cs @@ -0,0 +1,1528 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230504131610_AddedPrinterSpecificationsGlossary")] + partial class AddedPrinterSpecificationsGlossary + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230504131610_AddedPrinterSpecificationsGlossary.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230504131610_AddedPrinterSpecificationsGlossary.cs new file mode 100644 index 0000000..b41a13c --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230504131610_AddedPrinterSpecificationsGlossary.cs @@ -0,0 +1,71 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class AddedPrinterSpecificationsGlossary : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.InsertData( + schema: "CustomFields", + table: "CustomFields", + columns: new[] { "Id", "DefaultValue", "Deleted", "FieldType", "Guid", "MaxEntries", "MinEntries", "Name" }, + values: new object[] { 1L, "", false, 7, new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), 1L, 1L, "Print Specification Form Template" }); + + migrationBuilder.InsertData( + schema: "Glossaries", + table: "Glossaries", + columns: new[] { "Id", "Deleted", "Guid", "Name", "ParentId" }, + values: new object[] { 3L, false, new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), "Print Specifications", 1L }); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92")); + + migrationBuilder.InsertData( + schema: "Glossaries", + table: "GlossaryCustomFields", + columns: new[] { "Id", "CustomFieldId", "GlossaryId" }, + values: new object[] { 1L, 1L, 3L }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + schema: "Glossaries", + table: "GlossaryCustomFields", + keyColumn: "Id", + keyValue: 1L); + + migrationBuilder.DeleteData( + schema: "CustomFields", + table: "CustomFields", + keyColumn: "Id", + keyValue: 1L); + + migrationBuilder.DeleteData( + schema: "Glossaries", + table: "Glossaries", + keyColumn: "Id", + keyValue: 3L); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + column: "Guid", + value: new Guid("9f0a5037-44a9-45cf-8025-d5ae65f5f9b9")); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230607090003_MissingUniqueContraints.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230607090003_MissingUniqueContraints.Designer.cs new file mode 100644 index 0000000..e91133f --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230607090003_MissingUniqueContraints.Designer.cs @@ -0,0 +1,1538 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230607090003_MissingUniqueContraints")] + partial class MissingUniqueContraints + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230607090003_MissingUniqueContraints.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230607090003_MissingUniqueContraints.cs new file mode 100644 index 0000000..d2851d4 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230607090003_MissingUniqueContraints.cs @@ -0,0 +1,130 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class MissingUniqueContraints : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Specifications_SiteId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropIndex( + name: "IX_Sites_OrganisationId", + schema: "Printer", + table: "Sites"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Specifications", + type: "nvarchar(450)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Sites", + type: "nvarchar(450)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Organisations", + type: "nvarchar(450)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_SiteId_Name", + schema: "Printer", + table: "Specifications", + columns: new[] { "SiteId", "Name" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Sites_OrganisationId_Name", + schema: "Printer", + table: "Sites", + columns: new[] { "OrganisationId", "Name" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Organisations_Name", + schema: "Printer", + table: "Organisations", + column: "Name", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Specifications_SiteId_Name", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropIndex( + name: "IX_Sites_OrganisationId_Name", + schema: "Printer", + table: "Sites"); + + migrationBuilder.DropIndex( + name: "IX_Organisations_Name", + schema: "Printer", + table: "Organisations"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Specifications", + type: "nvarchar(max)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Sites", + type: "nvarchar(max)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Organisations", + type: "nvarchar(max)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_SiteId", + schema: "Printer", + table: "Specifications", + column: "SiteId"); + + migrationBuilder.CreateIndex( + name: "IX_Sites_OrganisationId", + schema: "Printer", + table: "Sites", + column: "OrganisationId"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230801141901_AddCustomFieldNumbers.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230801141901_AddCustomFieldNumbers.Designer.cs new file mode 100644 index 0000000..414e7ab --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230801141901_AddCustomFieldNumbers.Designer.cs @@ -0,0 +1,1579 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20230801141901_AddCustomFieldNumbers")] + partial class AddCustomFieldNumbers + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230801141901_AddCustomFieldNumbers.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230801141901_AddCustomFieldNumbers.cs new file mode 100644 index 0000000..78f8a39 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20230801141901_AddCustomFieldNumbers.cs @@ -0,0 +1,52 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class AddCustomFieldNumbers : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CustomFieldNumbers", + schema: "CustomFields", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomFieldId = table.Column(type: "bigint", nullable: false), + MinimumValue = table.Column(type: "decimal(28,8)", precision: 28, scale: 8, nullable: true), + MaximumValue = table.Column(type: "decimal(28,8)", precision: 28, scale: 8, nullable: true), + Step = table.Column(type: "decimal(28,8)", precision: 28, scale: 8, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomFieldNumbers", x => x.Id); + table.ForeignKey( + name: "FK_CustomFieldNumbers_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldNumbers_CustomFieldId", + schema: "CustomFields", + table: "CustomFieldNumbers", + column: "CustomFieldId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CustomFieldNumbers", + schema: "CustomFields"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231003144150_ExceptionLogging.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231003144150_ExceptionLogging.Designer.cs new file mode 100644 index 0000000..1679c33 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231003144150_ExceptionLogging.Designer.cs @@ -0,0 +1,1615 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20231003144150_ExceptionLogging")] + partial class ExceptionLogging + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231003144150_ExceptionLogging.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231003144150_ExceptionLogging.cs new file mode 100644 index 0000000..ef403ad --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231003144150_ExceptionLogging.cs @@ -0,0 +1,42 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class ExceptionLogging : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ExceptionLogs", + schema: "Diagnostics", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Application = table.Column(type: "nvarchar(max)", nullable: false), + ExceptionJson = table.Column(type: "nvarchar(max)", nullable: false), + Message = table.Column(type: "nvarchar(max)", nullable: false), + StackTrace = table.Column(type: "nvarchar(max)", nullable: false), + SupportingData = table.Column(type: "nvarchar(max)", nullable: false), + OccuredAt = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ExceptionLogs", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ExceptionLogs", + schema: "Diagnostics"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231110095405_AddCustomFieldText.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231110095405_AddCustomFieldText.Designer.cs new file mode 100644 index 0000000..2185c9f --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231110095405_AddCustomFieldText.Designer.cs @@ -0,0 +1,1647 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20231110095405_AddCustomFieldText")] + partial class AddCustomFieldText + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231110095405_AddCustomFieldText.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231110095405_AddCustomFieldText.cs new file mode 100644 index 0000000..b3f73ae --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20231110095405_AddCustomFieldText.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class AddCustomFieldText : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CustomFieldTexts", + schema: "CustomFields", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomFieldId = table.Column(type: "bigint", nullable: false), + MultiLine = table.Column(type: "bit", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomFieldTexts", x => x.Id); + table.ForeignKey( + name: "FK_CustomFieldTexts_CustomFields_CustomFieldId", + column: x => x.CustomFieldId, + principalSchema: "CustomFields", + principalTable: "CustomFields", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_CustomFieldTexts_CustomFieldId", + schema: "CustomFields", + table: "CustomFieldTexts", + column: "CustomFieldId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CustomFieldTexts", + schema: "CustomFields"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240123095808_PasswordResetCompletedEmailAdded.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240123095808_PasswordResetCompletedEmailAdded.Designer.cs new file mode 100644 index 0000000..54909ae --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240123095808_PasswordResetCompletedEmailAdded.Designer.cs @@ -0,0 +1,1657 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20240123095808_PasswordResetCompletedEmailAdded")] + partial class PasswordResetCompletedEmailAdded + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact you admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240123095808_PasswordResetCompletedEmailAdded.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240123095808_PasswordResetCompletedEmailAdded.cs new file mode 100644 index 0000000..08590f3 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240123095808_PasswordResetCompletedEmailAdded.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class PasswordResetCompletedEmailAdded : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.InsertData( + schema: "Mail", + table: "MailTemplates", + columns: new[] { "Deleted", "DomainId", "Guid", "MailType", "Subject", "TemplateDefinition" }, + values: new object[] { false, 1L, new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), 3, "Password successfully reset", "

Your password has been reset. Please contact you admin if this wasn't you.

" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Guid", + keyValue: new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c")); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240222154910_59647_ChangePasswordChangeEmail.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240222154910_59647_ChangePasswordChangeEmail.Designer.cs new file mode 100644 index 0000000..4aaf05c --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240222154910_59647_ChangePasswordChangeEmail.Designer.cs @@ -0,0 +1,1657 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20240222154910_59647_ChangePasswordChangeEmail")] + partial class _59647_ChangePasswordChangeEmail + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240222154910_59647_ChangePasswordChangeEmail.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240222154910_59647_ChangePasswordChangeEmail.cs new file mode 100644 index 0000000..e6e6eee --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240222154910_59647_ChangePasswordChangeEmail.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class _59647_ChangePasswordChangeEmail : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.UpdateData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Guid", + keyValue: "421B67C7-5F4B-4CAD-ADC5-528E2921790C", + column: "TemplateDefinition", + value: "

Your password has been reset. Please contact your admin if this wasn't you.

"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.UpdateData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Guid", + keyValue: "421B67C7-5F4B-4CAD-ADC5-528E2921790C", + column: "TemplateDefinition", + value: "

Your password has been reset. Please contact you admin if this wasn't you.

"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240614133301_Sso Support tables.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240614133301_Sso Support tables.Designer.cs new file mode 100644 index 0000000..e46e2b8 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240614133301_Sso Support tables.Designer.cs @@ -0,0 +1,1771 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20240614133301_Sso Support tables")] + partial class SsoSupporttables + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240614133301_Sso Support tables.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240614133301_Sso Support tables.cs new file mode 100644 index 0000000..01bed04 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240614133301_Sso Support tables.cs @@ -0,0 +1,194 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SsoSupporttables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "SsoProviderId", + schema: "UserManager", + table: "Users", + type: "bigint", + nullable: true); + + migrationBuilder.AddColumn( + name: "SsoSubject", + schema: "UserManager", + table: "Users", + type: "nvarchar(max)", + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "SsoProviderId", + schema: "Domain", + table: "Domains", + type: "bigint", + nullable: true); + + migrationBuilder.CreateTable( + name: "SingleUseGuids", + schema: "UserManager", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "bigint", nullable: false), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Expires = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SingleUseGuids", x => x.Id); + table.ForeignKey( + name: "FK_SingleUseGuids_Users_UserId", + column: x => x.UserId, + principalSchema: "UserManager", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SsoProviders", + schema: "UserManager", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(450)", nullable: false), + ClientId = table.Column(type: "nvarchar(max)", nullable: false), + ClientSecret = table.Column(type: "nvarchar(max)", nullable: false), + ValidIssuer = table.Column(type: "nvarchar(max)", nullable: false), + AuthorizationEndpoint = table.Column(type: "nvarchar(max)", nullable: false), + TokenEndpoint = table.Column(type: "nvarchar(max)", nullable: false), + IsPublic = table.Column(type: "bit", nullable: false), + Deleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SsoProviders", x => x.Id); + }); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Domains", + keyColumn: "Id", + keyValue: 1L, + column: "SsoProviderId", + value: null); + + migrationBuilder.UpdateData( + schema: "UserManager", + table: "Users", + keyColumn: "Id", + keyValue: 1L, + columns: new[] { "SsoProviderId", "SsoSubject" }, + values: new object[] { null, "" }); + + migrationBuilder.CreateIndex( + name: "IX_Users_SsoProviderId", + schema: "UserManager", + table: "Users", + column: "SsoProviderId"); + + migrationBuilder.CreateIndex( + name: "IX_Domains_SsoProviderId", + schema: "Domain", + table: "Domains", + column: "SsoProviderId"); + + migrationBuilder.CreateIndex( + name: "IX_SingleUseGuids_Guid", + schema: "UserManager", + table: "SingleUseGuids", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_SingleUseGuids_UserId", + schema: "UserManager", + table: "SingleUseGuids", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_SsoProviders_Name", + schema: "UserManager", + table: "SsoProviders", + column: "Name", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_Domains_SsoProviders_SsoProviderId", + schema: "Domain", + table: "Domains", + column: "SsoProviderId", + principalSchema: "UserManager", + principalTable: "SsoProviders", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Users_SsoProviders_SsoProviderId", + schema: "UserManager", + table: "Users", + column: "SsoProviderId", + principalSchema: "UserManager", + principalTable: "SsoProviders", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Domains_SsoProviders_SsoProviderId", + schema: "Domain", + table: "Domains"); + + migrationBuilder.DropForeignKey( + name: "FK_Users_SsoProviders_SsoProviderId", + schema: "UserManager", + table: "Users"); + + migrationBuilder.DropTable( + name: "SingleUseGuids", + schema: "UserManager"); + + migrationBuilder.DropTable( + name: "SsoProviders", + schema: "UserManager"); + + migrationBuilder.DropIndex( + name: "IX_Users_SsoProviderId", + schema: "UserManager", + table: "Users"); + + migrationBuilder.DropIndex( + name: "IX_Domains_SsoProviderId", + schema: "Domain", + table: "Domains"); + + migrationBuilder.DropColumn( + name: "SsoProviderId", + schema: "UserManager", + table: "Users"); + + migrationBuilder.DropColumn( + name: "SsoSubject", + schema: "UserManager", + table: "Users"); + + migrationBuilder.DropColumn( + name: "SsoProviderId", + schema: "Domain", + table: "Domains"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240902140648_Sso Support Tables #2.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240902140648_Sso Support Tables #2.Designer.cs new file mode 100644 index 0000000..bd5aba7 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240902140648_Sso Support Tables #2.Designer.cs @@ -0,0 +1,1774 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20240902140648_Sso Support Tables #2")] + partial class SsoSupportTables2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240902140648_Sso Support Tables #2.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240902140648_Sso Support Tables #2.cs new file mode 100644 index 0000000..fbbff4b --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20240902140648_Sso Support Tables #2.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SsoSupportTables2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Guid", + schema: "UserManager", + table: "SsoProviders", + type: "uniqueidentifier", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Guid", + schema: "UserManager", + table: "SsoProviders"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241009122056_specification foreign key.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241009122056_specification foreign key.Designer.cs new file mode 100644 index 0000000..1eb4262 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241009122056_specification foreign key.Designer.cs @@ -0,0 +1,1786 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20241009122056_specification foreign key")] +#pragma warning disable CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + partial class specificationforeignkey +#pragma warning restore CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("FormInstanceId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SiteId", "Name") + .IsUnique(); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany() + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormInstance"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241009122056_specification foreign key.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241009122056_specification foreign key.cs new file mode 100644 index 0000000..949a474 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241009122056_specification foreign key.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// +#pragma warning disable CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + public partial class specificationforeignkey : Migration +#pragma warning restore CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_Specifications_FormInstanceId", + schema: "Printer", + table: "Specifications", + column: "FormInstanceId"); + + migrationBuilder.AddForeignKey( + name: "FK_Specifications_FormInstances_FormInstanceId", + schema: "Printer", + table: "Specifications", + column: "FormInstanceId", + principalSchema: "Forms", + principalTable: "FormInstances", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Specifications_FormInstances_FormInstanceId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropIndex( + name: "IX_Specifications_FormInstanceId", + schema: "Printer", + table: "Specifications"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241211183359_SpecificationChanges.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241211183359_SpecificationChanges.Designer.cs new file mode 100644 index 0000000..eddde5c --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241211183359_SpecificationChanges.Designer.cs @@ -0,0 +1,1783 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20241211183359_SpecificationChanges")] + partial class SpecificationChanges + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241211183359_SpecificationChanges.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241211183359_SpecificationChanges.cs new file mode 100644 index 0000000..b9c2955 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20241211183359_SpecificationChanges.cs @@ -0,0 +1,122 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SpecificationChanges : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Specifications_FormInstances_FormInstanceId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropIndex( + name: "IX_Specifications_FormInstanceId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropIndex( + name: "IX_Specifications_SiteId_Name", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Specifications", + type: "nvarchar(max)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + + migrationBuilder.AddColumn( + name: "SigmaId", + schema: "Printer", + table: "Specifications", + type: "bigint", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_SsoProviders_Guid", + schema: "UserManager", + table: "SsoProviders", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_SigmaId", + schema: "Printer", + table: "Specifications", + column: "SigmaId", + unique: true, + filter: "[SigmaId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_SiteId", + schema: "Printer", + table: "Specifications", + column: "SiteId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_SsoProviders_Guid", + schema: "UserManager", + table: "SsoProviders"); + + migrationBuilder.DropIndex( + name: "IX_Specifications_SigmaId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropIndex( + name: "IX_Specifications_SiteId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropColumn( + name: "SigmaId", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Specifications", + type: "nvarchar(450)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_FormInstanceId", + schema: "Printer", + table: "Specifications", + column: "FormInstanceId"); + + migrationBuilder.CreateIndex( + name: "IX_Specifications_SiteId_Name", + schema: "Printer", + table: "Specifications", + columns: ["SiteId", "Name"], + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_Specifications_FormInstances_FormInstanceId", + schema: "Printer", + table: "Specifications", + column: "FormInstanceId", + principalSchema: "Forms", + principalTable: "FormInstances", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103113850_SigmaIdForSiteTable.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103113850_SigmaIdForSiteTable.Designer.cs new file mode 100644 index 0000000..e1ca91f --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103113850_SigmaIdForSiteTable.Designer.cs @@ -0,0 +1,1786 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250103113850_SigmaIdForSiteTable")] + partial class SigmaIdForSiteTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId", "Name") + .IsUnique(); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103113850_SigmaIdForSiteTable.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103113850_SigmaIdForSiteTable.cs new file mode 100644 index 0000000..a26126e --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103113850_SigmaIdForSiteTable.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SigmaIdForSiteTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "SigmaId", + schema: "Printer", + table: "Sites", + type: "bigint", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SigmaId", + schema: "Printer", + table: "Sites"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103145703_SiteNameNotUnique.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103145703_SiteNameNotUnique.Designer.cs new file mode 100644 index 0000000..de41def --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103145703_SiteNameNotUnique.Designer.cs @@ -0,0 +1,1789 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250103145703_SiteNameNotUnique")] + partial class SiteNameNotUnique + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103145703_SiteNameNotUnique.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103145703_SiteNameNotUnique.cs new file mode 100644 index 0000000..2f07e01 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250103145703_SiteNameNotUnique.cs @@ -0,0 +1,72 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SiteNameNotUnique : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Sites_OrganisationId_Name", + schema: "Printer", + table: "Sites"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Sites", + type: "nvarchar(max)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + + migrationBuilder.CreateIndex( + name: "IX_Sites_OrganisationId", + schema: "Printer", + table: "Sites", + column: "OrganisationId"); + + migrationBuilder.CreateIndex( + name: "IX_Sites_SigmaId", + schema: "Printer", + table: "Sites", + column: "SigmaId", + unique: true, + filter: "[SigmaId] IS NOT NULL"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Sites_OrganisationId", + schema: "Printer", + table: "Sites"); + + migrationBuilder.DropIndex( + name: "IX_Sites_SigmaId", + schema: "Printer", + table: "Sites"); + + migrationBuilder.AlterColumn( + name: "Name", + schema: "Printer", + table: "Sites", + type: "nvarchar(450)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.CreateIndex( + name: "IX_Sites_OrganisationId_Name", + schema: "Printer", + table: "Sites", + columns: new[] { "OrganisationId", "Name" }, + unique: true); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250116161837_SpecificationDomains.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250116161837_SpecificationDomains.Designer.cs new file mode 100644 index 0000000..f9a5f78 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250116161837_SpecificationDomains.Designer.cs @@ -0,0 +1,1836 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250116161837_SpecificationDomains")] + partial class SpecificationDomains + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SpecificationDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("SpecificationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("SpecificationId", "DomainId"); + + b.HasIndex("DomainId"); + + b.ToTable("SpecificationDomains", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SpecificationDomain", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Specification", "Specification") + .WithMany("Domains") + .HasForeignKey("SpecificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("Specification"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Navigation("Domains"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250116161837_SpecificationDomains.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250116161837_SpecificationDomains.cs new file mode 100644 index 0000000..83055d2 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250116161837_SpecificationDomains.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SpecificationDomains : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SpecificationDomains", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SpecificationId = table.Column(type: "bigint", nullable: false), + DomainId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SpecificationDomains", x => x.Id); + table.UniqueConstraint("AK_SpecificationDomains_SpecificationId_DomainId", x => new { x.SpecificationId, x.DomainId }); + table.ForeignKey( + name: "FK_SpecificationDomains_Domains_DomainId", + column: x => x.DomainId, + principalSchema: "Domain", + principalTable: "Domains", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_SpecificationDomains_Specifications_SpecificationId", + column: x => x.SpecificationId, + principalSchema: "Printer", + principalTable: "Specifications", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_SpecificationDomains_DomainId", + schema: "Printer", + table: "SpecificationDomains", + column: "DomainId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SpecificationDomains", + schema: "Printer"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250122112632_SunriseDomainUpgrade.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250122112632_SunriseDomainUpgrade.Designer.cs new file mode 100644 index 0000000..402077c --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250122112632_SunriseDomainUpgrade.Designer.cs @@ -0,0 +1,1854 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250122112632_SunriseDomainUpgrade")] + partial class SunriseDomainUpgrade + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SpecificationDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("SpecificationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("SpecificationId", "DomainId"); + + b.HasIndex("DomainId"); + + b.ToTable("SpecificationDomains", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SpecificationDomain", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Specification", "Specification") + .WithMany("Domains") + .HasForeignKey("SpecificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("Specification"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Navigation("Domains"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250122112632_SunriseDomainUpgrade.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250122112632_SunriseDomainUpgrade.cs new file mode 100644 index 0000000..6b0f8d3 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250122112632_SunriseDomainUpgrade.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class SunriseDomainUpgrade : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "SunriseAppId", + schema: "Domain", + table: "Domains", + type: "nvarchar(128)", + maxLength: 128, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "SunriseCategoryId", + schema: "Domain", + table: "Domains", + type: "nvarchar(16)", + maxLength: 16, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "SunriseHostname", + schema: "Domain", + table: "Domains", + type: "nvarchar(16)", + maxLength: 16, + nullable: false, + defaultValue: ""); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Domains", + keyColumn: "Id", + keyValue: 1L, + columns: new[] { "SunriseAppId", "SunriseCategoryId", "SunriseHostname" }, + values: new object[] { "", "", "" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SunriseAppId", + schema: "Domain", + table: "Domains"); + + migrationBuilder.DropColumn( + name: "SunriseCategoryId", + schema: "Domain", + table: "Domains"); + + migrationBuilder.DropColumn( + name: "SunriseHostname", + schema: "Domain", + table: "Domains"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250123125752_AddSigmaIdToDomains.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250123125752_AddSigmaIdToDomains.Designer.cs new file mode 100644 index 0000000..8565467 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250123125752_AddSigmaIdToDomains.Designer.cs @@ -0,0 +1,1857 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250123125752_AddSigmaIdToDomains")] + partial class AddSigmaIdToDomains + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SpecificationDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("SpecificationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("SpecificationId", "DomainId"); + + b.HasIndex("DomainId"); + + b.ToTable("SpecificationDomains", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SpecificationDomain", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Specification", "Specification") + .WithMany("Domains") + .HasForeignKey("SpecificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("Specification"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Navigation("Domains"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250123125752_AddSigmaIdToDomains.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250123125752_AddSigmaIdToDomains.cs new file mode 100644 index 0000000..f8844c7 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250123125752_AddSigmaIdToDomains.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class AddSigmaIdToDomains : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "SigmaId", + schema: "Domain", + table: "Domains", + type: "bigint", + nullable: true); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Domains", + keyColumn: "Id", + keyValue: 1L, + column: "SigmaId", + value: null); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SigmaId", + schema: "Domain", + table: "Domains"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250124105912_RemoveSpecificationDomainTable.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250124105912_RemoveSpecificationDomainTable.Designer.cs new file mode 100644 index 0000000..6503506 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250124105912_RemoveSpecificationDomainTable.Designer.cs @@ -0,0 +1,1810 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250124105912_RemoveSpecificationDomainTable")] + partial class RemoveSpecificationDomainTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250124105912_RemoveSpecificationDomainTable.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250124105912_RemoveSpecificationDomainTable.cs new file mode 100644 index 0000000..847b863 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250124105912_RemoveSpecificationDomainTable.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class RemoveSpecificationDomainTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SpecificationDomains", + schema: "Printer"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SpecificationDomains", + schema: "Printer", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + DomainId = table.Column(type: "bigint", nullable: false), + SpecificationId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SpecificationDomains", x => x.Id); + table.UniqueConstraint("AK_SpecificationDomains_SpecificationId_DomainId", x => new { x.SpecificationId, x.DomainId }); + table.ForeignKey( + name: "FK_SpecificationDomains_Domains_DomainId", + column: x => x.DomainId, + principalSchema: "Domain", + principalTable: "Domains", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_SpecificationDomains_Specifications_SpecificationId", + column: x => x.SpecificationId, + principalSchema: "Printer", + principalTable: "Specifications", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_SpecificationDomains_DomainId", + schema: "Printer", + table: "SpecificationDomains", + column: "DomainId"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250129162255_AddLastUpdateColumn.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250129162255_AddLastUpdateColumn.Designer.cs new file mode 100644 index 0000000..332dd73 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250129162255_AddLastUpdateColumn.Designer.cs @@ -0,0 +1,1901 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250129162255_AddLastUpdateColumn")] + partial class AddLastUpdateColumn + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)) + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250129162255_AddLastUpdateColumn.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250129162255_AddLastUpdateColumn.cs new file mode 100644 index 0000000..62b05f4 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250129162255_AddLastUpdateColumn.cs @@ -0,0 +1,461 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class AddLastUpdateColumn : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Domain", + table: "UserRoles", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "UserManager", + table: "SsoProviders", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Printer", + table: "Specifications", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Printer", + table: "Sites", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Printer", + table: "SiteContacts", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Sequences", + table: "Sequences", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Domain", + table: "Roles", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Domain", + table: "RoleAccess", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Printer", + table: "Organisations", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Printer", + table: "OrganisationContacts", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Mail", + table: "MailTemplates", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Glossaries", + table: "GlossaryCustomFieldValues", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Glossaries", + table: "GlossaryCustomFields", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Glossaries", + table: "Glossaries", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormTemplateVersions", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormTemplates", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormInstances", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormFieldInstances", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Domain", + table: "Domains", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldTexts", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldSequences", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFields", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldNumbers", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldGlossaries", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldFormTemplates", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.AddColumn( + name: "LastUpdated", + schema: "Contacts", + table: "Contacts", + type: "datetimeoffset", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "CustomFields", + table: "CustomFields", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Domains", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Glossaries", + table: "Glossaries", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Glossaries", + table: "Glossaries", + keyColumn: "Id", + keyValue: 2L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Glossaries", + table: "Glossaries", + keyColumn: "Id", + keyValue: 3L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Glossaries", + table: "GlossaryCustomFields", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Id", + keyValue: 2L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Id", + keyValue: 3L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Mail", + table: "MailTemplates", + keyColumn: "Id", + keyValue: 4L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Roles", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "Roles", + keyColumn: "Id", + keyValue: 2L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + + migrationBuilder.UpdateData( + schema: "Domain", + table: "UserRoles", + keyColumn: "Id", + keyValue: 1L, + column: "LastUpdated", + value: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Domain", + table: "UserRoles"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "UserManager", + table: "SsoProviders"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Printer", + table: "Specifications"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Printer", + table: "Sites"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Printer", + table: "SiteContacts"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Sequences", + table: "Sequences"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Domain", + table: "Roles"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Domain", + table: "RoleAccess"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Printer", + table: "Organisations"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Printer", + table: "OrganisationContacts"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Mail", + table: "MailTemplates"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Glossaries", + table: "GlossaryCustomFieldValues"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Glossaries", + table: "GlossaryCustomFields"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Glossaries", + table: "Glossaries"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormTemplateVersions"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormTemplates"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormInstances"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Forms", + table: "FormFieldInstances"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Domain", + table: "Domains"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldTexts"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldSequences"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFields"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldNumbers"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldGlossaries"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "CustomFields", + table: "CustomFieldFormTemplates"); + + migrationBuilder.DropColumn( + name: "LastUpdated", + schema: "Contacts", + table: "Contacts"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250317164548_ExternalKeySupport.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250317164548_ExternalKeySupport.Designer.cs new file mode 100644 index 0000000..10d1981 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250317164548_ExternalKeySupport.Designer.cs @@ -0,0 +1,1974 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20250317164548_ExternalKeySupport")] + partial class ExternalKeySupport + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)) + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ExternalSystemId") + .HasColumnType("bigint"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("EntityName", "PrimaryKey") + .IsUnique(); + + b.HasIndex("ExternalSystemId", "ExternalId") + .IsUnique(); + + b.ToTable("ExternalKeys", "Miscellaneous"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalSystem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("SystemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("SystemName") + .IsUnique(); + + b.ToTable("ExternalSystems", "Miscellaneous"); + + b.HasData( + new + { + Id = 1L, + SystemName = "e-flow" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalKey", b => + { + b.HasOne("e_suite.Database.Core.Tables.Miscellaneous.ExternalSystem", "ExternalSystem") + .WithMany() + .HasForeignKey("ExternalSystemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ExternalSystem"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250317164548_ExternalKeySupport.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250317164548_ExternalKeySupport.cs new file mode 100644 index 0000000..cfb8cf5 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20250317164548_ExternalKeySupport.cs @@ -0,0 +1,94 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class ExternalKeySupport : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "Miscellaneous"); + + migrationBuilder.CreateTable( + name: "ExternalSystems", + schema: "Miscellaneous", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SystemName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ExternalSystems", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ExternalKeys", + schema: "Miscellaneous", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + EntityName = table.Column(type: "nvarchar(450)", nullable: false), + PrimaryKey = table.Column(type: "nvarchar(450)", nullable: false), + ExternalSystemId = table.Column(type: "bigint", nullable: false), + ExternalId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ExternalKeys", x => x.Id); + table.ForeignKey( + name: "FK_ExternalKeys_ExternalSystems_ExternalSystemId", + column: x => x.ExternalSystemId, + principalSchema: "Miscellaneous", + principalTable: "ExternalSystems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + schema: "Miscellaneous", + table: "ExternalSystems", + columns: ["Id", "SystemName"], + values: [1L, "e-flow"]); + + migrationBuilder.CreateIndex( + name: "IX_ExternalKeys_EntityName_PrimaryKey", + schema: "Miscellaneous", + table: "ExternalKeys", + columns: ["EntityName", "PrimaryKey"], + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ExternalKeys_ExternalSystemId_ExternalId", + schema: "Miscellaneous", + table: "ExternalKeys", + columns: ["ExternalSystemId", "ExternalId"], + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ExternalSystems_SystemName", + schema: "Miscellaneous", + table: "ExternalSystems", + column: "SystemName", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ExternalKeys", + schema: "Miscellaneous"); + + migrationBuilder.DropTable( + name: "ExternalSystems", + schema: "Miscellaneous"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20260119201244_WorkflowTables.Designer.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20260119201244_WorkflowTables.Designer.cs new file mode 100644 index 0000000..e9badb6 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20260119201244_WorkflowTables.Designer.cs @@ -0,0 +1,2076 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + [Migration("20260119201244_WorkflowTables")] + partial class WorkflowTables + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)) + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ExternalSystemId") + .HasColumnType("bigint"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("EntityName", "PrimaryKey") + .IsUnique(); + + b.HasIndex("ExternalSystemId", "ExternalId") + .IsUnique(); + + b.ToTable("ExternalKeys", "Miscellaneous"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalSystem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("SystemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("SystemName") + .IsUnique(); + + b.ToTable("ExternalSystems", "Miscellaneous"); + + b.HasData( + new + { + Id = 1L, + SystemName = "e-flow" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Workflow.Workflow", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Workflows", "Workflow"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Workflow.WorkflowVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActivityNameTemplate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Tasks") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.Property("WorkflowId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("WorkflowId", "Version") + .IsUnique(); + + b.ToTable("WorkflowVersions", "Workflow"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalKey", b => + { + b.HasOne("e_suite.Database.Core.Tables.Miscellaneous.ExternalSystem", "ExternalSystem") + .WithMany() + .HasForeignKey("ExternalSystemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ExternalSystem"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Workflow.WorkflowVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Workflow.Workflow", "Workflow") + .WithMany() + .HasForeignKey("WorkflowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("Workflow"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20260119201244_WorkflowTables.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20260119201244_WorkflowTables.cs new file mode 100644 index 0000000..f051dc0 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/20260119201244_WorkflowTables.cs @@ -0,0 +1,117 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + /// + public partial class WorkflowTables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "Workflow"); + + migrationBuilder.CreateTable( + name: "Workflows", + schema: "Workflow", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + LastUpdated = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Workflows", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "WorkflowVersions", + schema: "Workflow", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Guid = table.Column(type: "uniqueidentifier", nullable: false), + WorkflowId = table.Column(type: "bigint", nullable: false), + Version = table.Column(type: "bigint", nullable: false), + DomainId = table.Column(type: "bigint", nullable: false), + ActivityNameTemplate = table.Column(type: "nvarchar(max)", nullable: false), + Description = table.Column(type: "nvarchar(max)", nullable: false), + Tasks = table.Column(type: "nvarchar(max)", nullable: false), + Deleted = table.Column(type: "bit", nullable: false), + LastUpdated = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WorkflowVersions", x => x.Id); + table.ForeignKey( + name: "FK_WorkflowVersions_Domains_DomainId", + column: x => x.DomainId, + principalSchema: "Domain", + principalTable: "Domains", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_WorkflowVersions_Workflows_WorkflowId", + column: x => x.WorkflowId, + principalSchema: "Workflow", + principalTable: "Workflows", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Workflows_Guid", + schema: "Workflow", + table: "Workflows", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Workflows_Name", + schema: "Workflow", + table: "Workflows", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_WorkflowVersions_DomainId", + schema: "Workflow", + table: "WorkflowVersions", + column: "DomainId"); + + migrationBuilder.CreateIndex( + name: "IX_WorkflowVersions_Guid", + schema: "Workflow", + table: "WorkflowVersions", + column: "Guid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_WorkflowVersions_WorkflowId_Version", + schema: "Workflow", + table: "WorkflowVersions", + columns: new[] { "WorkflowId", "Version" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "WorkflowVersions", + schema: "Workflow"); + + migrationBuilder.DropTable( + name: "Workflows", + schema: "Workflow"); + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/SqlEsuiteDatabaseDbContextModelSnapshot.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/SqlEsuiteDatabaseDbContextModelSnapshot.cs new file mode 100644 index 0000000..6e790d9 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/Migrations/SqlEsuiteDatabaseDbContextModelSnapshot.cs @@ -0,0 +1,2073 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using e_suite.Database.SqlServer; + +#nullable disable + +namespace esuite.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlEsuiteDatabaseDbContext))] + partial class SqlEsuiteDatabaseDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Fields") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UserDisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AuditDetails", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.Property("ParentAuditDrillDownEntityId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ChildAuditDrillDownEntityId"); + + b.HasIndex("ParentAuditDrillDownEntityId"); + + b.ToTable("AuditDrillHierarchies", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuditLogId") + .HasColumnType("bigint"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsPrimary") + .HasColumnType("bit"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.ToTable("AuditEntries", "Audit"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Contacts.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("JCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Contacts", "Contacts"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FieldType") + .HasColumnType("int"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaxEntries") + .HasColumnType("bigint"); + + b.Property("MinEntries") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CustomFields", "CustomFields"); + + b.HasData( + new + { + Id = 1L, + DefaultValue = "", + Deleted = false, + FieldType = 7, + Guid = new Guid("8d910089-3079-4a29-abad-8ddf82db6dbb"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MaxEntries = 1L, + MinEntries = 1L, + Name = "Print Specification Form Template" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("FormTemplateId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("FormTemplateId"); + + b.ToTable("CustomFieldFormTemplates", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("GlossaryId"); + + b.ToTable("CustomFieldGlossaries", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MaximumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("MinimumValue") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.Property("Step") + .HasPrecision(28, 8) + .HasColumnType("decimal(28,8)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldNumbers", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("SequenceId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("SequenceId"); + + b.ToTable("CustomFieldSequences", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MultiLine") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("CustomFieldTexts", "CustomFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.ExceptionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Application") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExceptionJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OccuredAt") + .HasColumnType("datetimeoffset"); + + b.Property("StackTrace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportingData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ExceptionLogs", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActionName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ActionParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ControllerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Host") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RequestType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDateTime") + .HasColumnType("datetimeoffset"); + + b.Property("Timings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("PerformanceReports", "Diagnostics"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Diagnostics.PerformanceThreshold", b => + { + b.Property("ControllerName") + .HasColumnType("nvarchar(450)"); + + b.Property("ActionName") + .HasColumnType("nvarchar(450)"); + + b.Property("RequestType") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalTimeMS") + .HasColumnType("int"); + + b.HasKey("ControllerName", "ActionName", "RequestType"); + + b.ToTable("PerformanceThresholds", "Diagnostics"); + + b.HasData( + new + { + ControllerName = "", + ActionName = "", + RequestType = "", + TotalTimeMS = 2000 + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SunriseAppId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SunriseCategoryId") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("SunriseHostname") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Domains", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("4eb1b0c7-e81b-4c9d-ba91-384ed47a1cf9"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Sun-Strategy", + SunriseAppId = "", + SunriseCategoryId = "", + SunriseHostname = "" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsAdministrator") + .HasColumnType("bit"); + + b.Property("IsSuperUser") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "Name") + .IsUnique(); + + b.ToTable("Roles", "Domain"); + + b.HasData( + new + { + Id = 1L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32d65817-4de4-4bd5-912e-2b33054a2171"), + IsAdministrator = false, + IsSuperUser = true, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Super Users" + }, + new + { + Id = 2L, + CanDelete = false, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2f77f57c-fe2c-4a36-ad17-5d902afc86cb"), + IsAdministrator = true, + IsSuperUser = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Administrators" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("RoleId", "AccessKey"); + + b.ToTable("RoleAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.Property("AccessKey") + .HasColumnType("int"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasIndex("DomainId"); + + b.HasIndex("UserId"); + + b.ToTable("UserAccess", "Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "Domain"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + RoleId = 1L, + UserId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("FormInstanceId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("FormFieldInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormTemplateVersionId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("FormTemplateVersionId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.ToTable("FormInstances", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FormTemplates", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("TemplateId") + .HasColumnType("bigint"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("FormTemplateVersions", "Forms"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ParentId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.HasIndex("Id", "ParentId") + .IsUnique() + .HasFilter("[ParentId] IS NOT NULL"); + + b.ToTable("Glossaries", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + Guid = new Guid("fa6566f8-b4b0-48c5-9985-336c9284796e"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "System" + }, + new + { + Id = 2L, + Deleted = false, + Guid = new Guid("90c48cf1-1a2b-4a76-b30b-260ecb149ccc"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Domain" + }, + new + { + Id = 3L, + Deleted = false, + Guid = new Guid("35eb8c23-4528-49a7-a798-b8bae3b06daf"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Name = "Print Specifications", + ParentId = 1L + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId"); + + b.HasIndex("CustomFieldId"); + + b.ToTable("GlossaryCustomFields", "Glossaries"); + + b.HasData( + new + { + Id = 1L, + CustomFieldId = 1L, + GlossaryId = 3L, + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)) + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomFieldId") + .HasColumnType("bigint"); + + b.Property("DisplayValue") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GlossaryId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Index") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasAlternateKey("GlossaryId", "CustomFieldId", "Index"); + + b.HasIndex("CustomFieldId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("GlossaryId", "CustomFieldId", "Index") + .IsUnique(); + + b.ToTable("GlossaryCustomFieldValues", "Glossaries"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MailType") + .HasColumnType("int"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateDefinition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("DomainId", "MailType") + .IsUnique(); + + b.ToTable("MailTemplates", "Mail"); + + b.HasData( + new + { + Id = 1L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("32b657af-5e17-47f3-b8dc-59580516b141"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 0, + Subject = "Confirmation e-mail", + TemplateDefinition = "

Please confirm your e-mail

Welcome to . Please click on this link to confirm your e-mail address is correct." + }, + new + { + Id = 2L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("77fff2b0-dd8c-43e6-a9fd-304c79850f81"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 2, + Subject = "Password reset", + TemplateDefinition = "

Please follow the link to reset your password


Reset Password" + }, + new + { + Id = 3L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("2e2d84a5-be1c-4e3b-a86a-bdafed42801b"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 1, + Subject = "Disable two factor authentication", + TemplateDefinition = "

Please follow the link to reset two factor authentication


Disable two factor authentication" + }, + new + { + Id = 4L, + Deleted = false, + DomainId = 1L, + Guid = new Guid("421b67c7-5f4b-4cad-adc5-528e2921790c"), + LastUpdated = new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MailType = 3, + Subject = "Password successfully reset", + TemplateDefinition = "

Your password has been reset. Please contact your admin if this wasn't you.

" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EntityName") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ExternalSystemId") + .HasColumnType("bigint"); + + b.Property("PrimaryKey") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("EntityName", "PrimaryKey") + .IsUnique(); + + b.HasIndex("ExternalSystemId", "ExternalId") + .IsUnique(); + + b.ToTable("ExternalKeys", "Miscellaneous"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalSystem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("SystemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("SystemName") + .IsUnique(); + + b.ToTable("ExternalSystems", "Miscellaneous"); + + b.HasData( + new + { + Id = 1L, + SystemName = "e-flow" + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Organisations", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("OrganisationId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("OrganisationContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("OrganisationId"); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.ToTable("Sites", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.Property("SiteId") + .HasColumnType("bigint"); + + b.Property("ContactId") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Primary") + .HasColumnType("bit"); + + b.HasKey("SiteId", "ContactId"); + + b.HasIndex("ContactId"); + + b.ToTable("SiteContacts", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("FormInstanceId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SigmaId") + .HasColumnType("bigint"); + + b.Property("SiteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("SigmaId") + .IsUnique() + .HasFilter("[SigmaId] IS NOT NULL"); + + b.HasIndex("SiteId"); + + b.ToTable("Specifications", "Printer"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt", b => + { + b.Property("IPAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AttemptedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("IPAddress", "AttemptedTime"); + + b.ToTable("FailedAccessAttempts", "Sentinel"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Sequences.Sequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("Increment") + .HasColumnType("bigint"); + + b.Property("LastIssueDate") + .HasColumnType("datetimeoffset"); + + b.Property("LastIssueValue") + .HasColumnType("bigint"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Pattern") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Rollover") + .HasColumnType("int"); + + b.Property("Seed") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Sequences", "Sequences"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EmailActionType") + .HasColumnType("int"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Token") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasAlternateKey("Token", "EmailActionType"); + + b.HasIndex("UserId"); + + b.ToTable("EmailUserActions", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("SingleUseGuids", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SsoProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ValidIssuer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SsoProviders", "UserManager"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("MiddleNames") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SsoProviderId") + .HasColumnType("bigint"); + + b.Property("SsoSubject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorAuthenticationKey") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UsingTwoFactorAuthentication") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SsoProviderId"); + + b.ToTable("Users", "UserManager"); + + b.HasData( + new + { + Id = 1L, + Active = true, + Created = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + DomainId = 1L, + Email = "testuser1@sun-strategy.com", + EmailConfirmed = true, + FirstName = "Test1", + Guid = new Guid("30cfcd5b-3385-43f1-b59a-fd35236f3d92"), + LastName = "User", + LastUpdated = new DateTimeOffset(new DateTime(2022, 6, 9, 12, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + MiddleNames = "", + Password = "AgAAAAIAACcQAAAAAAAAABDGmF9Hre4l8k9lkZAxBRJk0zNHD2b6xfKz4C7h6UjuirkoyoP2fVR6d9b7riT03UnL5yAgFh2pSSVQDx+nQ5PBjZRB9UG4u5FrY8W7ouA/+w==", + SsoSubject = "", + TwoFactorAuthenticationKey = "4EHHG42OWCN3L72TSRYSHTV6MRJXVOY3", + UsingTwoFactorAuthentication = false + }); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Workflow.Workflow", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Workflows", "Workflow"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Workflow.WorkflowVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActivityNameTemplate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Deleted") + .HasColumnType("bit"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DomainId") + .HasColumnType("bigint"); + + b.Property("Guid") + .HasColumnType("uniqueidentifier"); + + b.Property("LastUpdated") + .HasColumnType("datetimeoffset"); + + b.Property("Tasks") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.Property("WorkflowId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DomainId"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("WorkflowId", "Version") + .IsUnique(); + + b.ToTable("WorkflowVersions", "Workflow"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditDrillHierarchy", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ChildAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ChildAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditEntry", "ParentAuditDrillDownEntity") + .WithMany() + .HasForeignKey("ParentAuditDrillDownEntityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("ChildAuditDrillDownEntity"); + + b.Navigation("ParentAuditDrillDownEntity"); + }); + + modelBuilder.Entity("e_suite.Database.Audit.Tables.Audit.AuditEntry", b => + { + b.HasOne("e_suite.Database.Audit.Tables.Audit.AuditDetail", "AuditLog") + .WithMany() + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AuditLog"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldFormTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "FormTemplate") + .WithMany() + .HasForeignKey("FormTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormTemplate"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldGlossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany() + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldNumber", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldSequence", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Sequences.Sequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Sequence"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.CustomFields.CustomFieldText", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Domain", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.Role", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.RoleAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserAccess", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Domain.UserRole", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormFieldInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Forms.FormInstance", "FormInstance") + .WithMany("FormFields") + .HasForeignKey("FormInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("FormInstance"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", "FormTemplateVersion") + .WithMany() + .HasForeignKey("FormTemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FormTemplateVersion"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplateVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Forms.FormTemplate", "Template") + .WithMany("Versions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomField", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldDefinitions") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.GlossaryCustomFieldValue", b => + { + b.HasOne("e_suite.Database.Core.Tables.CustomFields.CustomField", "CustomField") + .WithMany() + .HasForeignKey("CustomFieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Glossaries.Glossary", "Glossary") + .WithMany("CustomFieldValues") + .HasForeignKey("GlossaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CustomField"); + + b.Navigation("Glossary"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Mail.MailTemplate", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Miscellaneous.ExternalKey", b => + { + b.HasOne("e_suite.Database.Core.Tables.Miscellaneous.ExternalSystem", "ExternalSystem") + .WithMany() + .HasForeignKey("ExternalSystemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ExternalSystem"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.OrganisationContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Organisation", "Organisation") + .WithMany("Sites") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.SiteContact", b => + { + b.HasOne("e_suite.Database.Core.Tables.Contacts.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Specification", b => + { + b.HasOne("e_suite.Database.Core.Tables.Printer.Site", "Site") + .WithMany("Specifications") + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.EmailUserAction", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.SingleUseGuid", b => + { + b.HasOne("e_suite.Database.Core.Tables.UserManager.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.UserManager.User", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.UserManager.SsoProvider", "SsoProvider") + .WithMany() + .HasForeignKey("SsoProviderId"); + + b.Navigation("Domain"); + + b.Navigation("SsoProvider"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Workflow.WorkflowVersion", b => + { + b.HasOne("e_suite.Database.Core.Tables.Domain.Domain", "Domain") + .WithMany() + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("e_suite.Database.Core.Tables.Workflow.Workflow", "Workflow") + .WithMany() + .HasForeignKey("WorkflowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("Workflow"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormInstance", b => + { + b.Navigation("FormFields"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Forms.FormTemplate", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Glossaries.Glossary", b => + { + b.Navigation("CustomFieldDefinitions"); + + b.Navigation("CustomFieldValues"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Organisation", b => + { + b.Navigation("Sites"); + }); + + modelBuilder.Entity("e_suite.Database.Core.Tables.Printer.Site", b => + { + b.Navigation("Specifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/SqlEsuiteDatabaseDbContext.cs b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/SqlEsuiteDatabaseDbContext.cs new file mode 100644 index 0000000..e7a4299 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/SqlEsuiteDatabaseDbContext.cs @@ -0,0 +1,20 @@ +using e_suite.Database.Core; +using eSuite.Core.Clock; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace e_suite.Database.SqlServer; + +public class SqlEsuiteDatabaseDbContext : EsuiteDatabaseDbContext +{ + public SqlEsuiteDatabaseDbContext(DbContextOptions options, IClock clock) : base(options, clock) + { + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.ConfigureWarnings(w => w.Ignore(SqlServerEventId.SavepointsDisabledBecauseOfMARS)); + optionsBuilder.ReplaceService(); + } +} \ No newline at end of file diff --git a/e-suite.Database.SqlServer/e-suite.Database.SqlServer/e-suite.Database.SqlServer.csproj b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/e-suite.Database.SqlServer.csproj new file mode 100644 index 0000000..c71f8a6 --- /dev/null +++ b/e-suite.Database.SqlServer/e-suite.Database.SqlServer/e-suite.Database.SqlServer.csproj @@ -0,0 +1,31 @@ + + + + net10.0 + e_suite.Database.SqlServer + enable + enable + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/e-suite.Database.SqlServer/nuget.config b/e-suite.Database.SqlServer/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Database.SqlServer/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/.gitattributes b/e-suite.Manager.BlockedIPs/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Manager.BlockedIPs/.gitignore b/e-suite.Manager.BlockedIPs/.gitignore new file mode 100644 index 0000000..196ba0f --- /dev/null +++ b/e-suite.Manager.BlockedIPs/.gitignore @@ -0,0 +1,366 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +##ncrunch +*.ncrunchsolution \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/.runsettings b/e-suite.Manager.BlockedIPs/.runsettings new file mode 100644 index 0000000..a43367b --- /dev/null +++ b/e-suite.Manager.BlockedIPs/.runsettings @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + .*microsoft.testplatform.* + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/README.md b/e-suite.Manager.BlockedIPs/README.md new file mode 100644 index 0000000..6c1e572 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/README.md @@ -0,0 +1 @@ +# e-suite.Manager.BlockedIPs \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/azure-pipelines.yml b/e-suite.Manager.BlockedIPs/azure-pipelines.yml new file mode 100644 index 0000000..294caab --- /dev/null +++ b/e-suite.Manager.BlockedIPs/azure-pipelines.yml @@ -0,0 +1,133 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.BlockedIPsManager/e-suite.Modules.BlockedIPsManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '70' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/e-suite.Manager.BlockedIPs.sln b/e-suite.Manager.BlockedIPs/e-suite.Manager.BlockedIPs.sln new file mode 100644 index 0000000..0cba7b9 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Manager.BlockedIPs.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33829.357 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.BlockedIPsManager", "e-suite.Modules.BlockedIPsManager\e-suite.Modules.BlockedIPsManager.csproj", "{F69664C1-DB5F-4646-BC10-8EE18BC8D062}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{D9FB7056-9D6B-49D9-AD25-7387B3BDF9ED}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{BBD3AD03-0677-4911-A50E-0C8EE6DE0FA7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.BlockedIPsManager.UnitTests", "e-suite.Modules.BlockedIPsManager.UnitTests\e-suite.Modules.BlockedIPsManager.UnitTests.csproj", "{2973BE3E-7B89-4E2F-B10F-65478F9E18C6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F69664C1-DB5F-4646-BC10-8EE18BC8D062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F69664C1-DB5F-4646-BC10-8EE18BC8D062}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F69664C1-DB5F-4646-BC10-8EE18BC8D062}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F69664C1-DB5F-4646-BC10-8EE18BC8D062}.Release|Any CPU.Build.0 = Release|Any CPU + {2973BE3E-7B89-4E2F-B10F-65478F9E18C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2973BE3E-7B89-4E2F-B10F-65478F9E18C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2973BE3E-7B89-4E2F-B10F-65478F9E18C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2973BE3E-7B89-4E2F-B10F-65478F9E18C6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BBD3AD03-0677-4911-A50E-0C8EE6DE0FA7} = {D9FB7056-9D6B-49D9-AD25-7387B3BDF9ED} + {2973BE3E-7B89-4E2F-B10F-65478F9E18C6} = {BBD3AD03-0677-4911-A50E-0C8EE6DE0FA7} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B04E8830-FF9B-4876-AC64-05B6425E8E20} + EndGlobalSection +EndGlobal diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/ExtensionsUnitTests.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/ExtensionsUnitTests.cs new file mode 100644 index 0000000..628718a --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/ExtensionsUnitTests.cs @@ -0,0 +1,29 @@ +using e_suite.Modules.BlockedIPsManager.Extensions; +using e_suite.Modules.BlockedIPsManager.UnitTests.Helpers; +using NUnit.Framework; + +namespace e_suite.Modules.BlockedIPsManager.UnitTests; + +public class ExtensionsUnitTests : BlockedIPsManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DoubleExtensionMethod_WhenCalled_ReturnsExpectedResult() + { + //Arrange + double pi = 3.14159; + + //Act + var result = pi.ToInteger(); + + //Assert + Assert.That(result, Is.Positive); + Assert.That(result, Is.EqualTo(3)); + Assert.Pass(); + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/GetBlockedIPsUnitTests.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/GetBlockedIPsUnitTests.cs new file mode 100644 index 0000000..8920b79 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/GetBlockedIPsUnitTests.cs @@ -0,0 +1,72 @@ +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.Modules.BlockedIPsManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.BlockedIPsManager.UnitTests; + +public class GetBlockedIPsUnitTests: BlockedIPsManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetBlockedIPs_FakeRepository_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var failedLoginAttemptOne = new FailedAccessAttempt + { + IPAddress = "127.0.0.1", + AttemptedTime = _fakeClock.GetNow.Subtract(TimeSpan.FromSeconds(10)), + }; + + var failedLoginAttemptTwo = new FailedAccessAttempt + { + IPAddress = "127.0.0.1", + AttemptedTime = _fakeClock.GetNow.Subtract(TimeSpan.FromSeconds(9)), + }; + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptOne); + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptTwo); + + //Act + var result = BlockedIPsManagerRepository.GetBlockedIPs(_fakeClock.GetNow).ToList(); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.Pass(); + } + + [Test] + public async Task GetBlockedIPs_Manager_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var paging = new Paging(); + + var failedLoginAttemptOne = new FailedAccessAttempt + { + IPAddress = "127.0.0.1", + AttemptedTime = _fakeClock.GetNow.Subtract(TimeSpan.FromSeconds(10)), + }; + + var failedLoginAttemptTwo = new FailedAccessAttempt + { + IPAddress = "127.0.0.1", + AttemptedTime = _fakeClock.GetNow.Subtract(TimeSpan.FromSeconds(9)), + }; + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptOne); + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptTwo); + + //Act + var result = await BlockedIPManager.GetBlockedIPs(paging, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + Assert.Pass(); + } +} \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/GetUnlockedMinutesUnitTests.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/GetUnlockedMinutesUnitTests.cs new file mode 100644 index 0000000..97b1fa5 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/GetUnlockedMinutesUnitTests.cs @@ -0,0 +1,28 @@ +using e_suite.Modules.BlockedIPsManager.UnitTests.Helpers; +using NUnit.Framework; + +namespace e_suite.Modules.BlockedIPsManager.UnitTests; + +public class GetUnlockedMinutesUnitTests : BlockedIPsManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetUnlockedMinutes_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var attemptedTime = new DateTimeOffset(DateTime.UtcNow.Subtract(new TimeSpan(10))); + var dateTimeNow = new DateTimeOffset(DateTime.UtcNow); + //Act + var result = BlockedIPsManager.GetUnlockedMinutes(attemptedTime, 60, dateTimeNow); + + //Assert + Assert.That(result, Is.Positive); + Assert.That(result, Is.EqualTo(59)); + Assert.Pass(); + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/Helpers/BlockedIPsManagerTestBase.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/Helpers/BlockedIPsManagerTestBase.cs new file mode 100644 index 0000000..37d4330 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/Helpers/BlockedIPsManagerTestBase.cs @@ -0,0 +1,19 @@ +using e_suite.API.Common; +using e_suite.Modules.BlockedIPsManager.UnitTests.Repository; +using e_suite.UnitTestCore; + +namespace e_suite.Modules.BlockedIPsManager.UnitTests.Helpers; + +public class BlockedIPsManagerTestBase: TestBase +{ + protected FakeBlockedIPsManagerRepository BlockedIPsManagerRepository { get; set; } = null!; + protected IBlockedIPsManager BlockedIPManager { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + BlockedIPsManagerRepository = new FakeBlockedIPsManagerRepository(); + + BlockedIPManager = new BlockedIPsManager(BlockedIPsManagerRepository, _fakeClock, _configuration); + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/Repository/FakeBlockedIPsManagerRepository.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/Repository/FakeBlockedIPsManagerRepository.cs new file mode 100644 index 0000000..c67bcc9 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/Repository/FakeBlockedIPsManagerRepository.cs @@ -0,0 +1,27 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.UnitTestCore; +using MockQueryable; + +namespace e_suite.Modules.BlockedIPsManager.UnitTests.Repository; + +public class FakeBlockedIPsManagerRepository : FakeRepository, IBlockedIPsManagerRepository +{ + public string IpAddress = string.Empty; + public DateTimeOffset EarliestAttemptTime = DateTimeOffset.MinValue; + public List FailedAccessAttempts = []; + + public IQueryable GetBlockedIPs(DateTimeOffset earliestAttemptTime) + { + return FailedAccessAttempts.BuildMock(); + } + + public Task UnBlockIP(AuditUserDetails auditUserDetails, string ipAddress, CancellationToken cancellationToken) + { + var failedAccessAttempt = FailedAccessAttempts.Where(i => i.IPAddress == ipAddress).First(); + + var removed = FailedAccessAttempts.Remove(failedAccessAttempt); + return Task.CompletedTask; + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/UnBlockIPUnitTests.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/UnBlockIPUnitTests.cs new file mode 100644 index 0000000..11af537 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/UnBlockIPUnitTests.cs @@ -0,0 +1,92 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.Modules.BlockedIPsManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.BlockedIPsManager.UnitTests; + +public class UnBlockIPUnitTests : BlockedIPsManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task UnBlockedIPAddress_FakeRepository_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Test User", + Comment = string.Empty + }; + + var dto = _fakeClock.GetNow.Subtract(new TimeSpan(10)); + + var failedLoginAttemptOne = new FailedAccessAttempt + { + IPAddress = "127.0.0.1", + AttemptedTime = dto, + }; + + var failedLoginAttemptTwo = new FailedAccessAttempt + { + IPAddress = "127.0.0.2", + AttemptedTime = dto, + }; + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptOne); + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptTwo); + + //Act + await BlockedIPsManagerRepository.UnBlockIP(auditDetails, "127.0.0.1", CancellationToken.None); + var result = BlockedIPsManagerRepository.GetBlockedIPs(_fakeClock.GetNow).ToList(); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.Pass(); + } + + [Test] + public async Task UnBlockedIPAddress_Manager_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var paging = new Paging(); + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Test User", + Comment = string.Empty + }; + + var dto = new DateTimeOffset(new DateTime(2023, 09, 8, 0, 0, 0, DateTimeKind.Utc)).ToOffset(TimeSpan.FromHours(0)); + + var failedLoginAttemptOne = new FailedAccessAttempt + { + IPAddress = "127.0.0.1", + AttemptedTime = dto, + }; + + var failedLoginAttemptTwo = new FailedAccessAttempt + { + IPAddress = "127.0.0.2", + AttemptedTime = dto, + }; + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptOne); + BlockedIPsManagerRepository.FailedAccessAttempts.Add(failedLoginAttemptTwo); + + //Act + await BlockedIPManager.UnblockIPAddress(auditDetails, "127.0.0.1", CancellationToken.None); + var result = await BlockedIPManager.GetBlockedIPs(paging, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + Assert.Pass(); + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/e-suite.Modules.BlockedIPsManager.UnitTests.csproj b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/e-suite.Modules.BlockedIPsManager.UnitTests.csproj new file mode 100644 index 0000000..a707443 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager.UnitTests/e-suite.Modules.BlockedIPsManager.UnitTests.csproj @@ -0,0 +1,32 @@ + + + + net10.0 + e_suite.Modules.BlockedIPsManager.UnitTests + enable + enable + + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/BlockedIPsManager.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/BlockedIPsManager.cs new file mode 100644 index 0000000..803f52f --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/BlockedIPsManager.cs @@ -0,0 +1,94 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Modules.BlockedIPsManager.Extensions; +using e_suite.Utilities.Pagination; +using eSuite.Core.Clock; +using Microsoft.Extensions.Configuration; +using System.Linq.Expressions; +using MockQueryable; + +namespace e_suite.Modules.BlockedIPsManager; + +public class BlockedIPsManager : IBlockedIPsManager +{ + private readonly IClock _clock; + private readonly IConfiguration _configuration; + private readonly IBlockedIPsManagerRepository _blockedIPsManagerRepository; + + public BlockedIPsManager(IBlockedIPsManagerRepository blockedIPsManagerRepository, IClock clock, IConfiguration configuration) + { + _blockedIPsManagerRepository = blockedIPsManagerRepository; + _clock = clock; + _configuration = configuration; + } + + public async Task> GetBlockedIPs(Paging paging, CancellationToken cancellationToken) + { + //Can I make this move, its a copied code from the sentinal + var loginAttemptTimeoutMinutes = _configuration.GetValue("Sentinel:LoginAttemptTimeoutMinutes"); + var maxLoginAttempts = _configuration.GetValue("Sentinel:MaxLoginAttempts"); + + var earliestAttemptTime = _clock.GetNow.AddMinutes(-loginAttemptTimeoutMinutes); + + var blockedIPs = _blockedIPsManagerRepository.GetBlockedIPs(earliestAttemptTime); + + var dateTimeNow = _clock.GetNow; + + var data = blockedIPs.GroupBy(g => g.IPAddress) + .Select(x => new BlockedIPs { + IPAddress = x.First().IPAddress, + NumberOfAttempts = x.Count(), + BlockedAt = x.Max(t => t.AttemptedTime), + UnblockedIn = GetUnlockedMinutes(x.Min(t => t.AttemptedTime), loginAttemptTimeoutMinutes, dateTimeNow).ToInteger() + }) + .ToList() + .BuildMock(); + + var paginatedData = await PaginatedData.Paginate(data, paging, + KeySelector, FilterSelector, cancellationToken); + + return new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data + }; + } + + public static double GetUnlockedMinutes(DateTimeOffset attemptedTime, int loginAttemptTimeoutMinutes, DateTimeOffset dateTimeNow) + { + return Math.Floor(attemptedTime.AddMinutes(loginAttemptTimeoutMinutes).Subtract(dateTimeNow).TotalMinutes); + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "ipaddress" => x => x.IPAddress.ToString().Contains(value), + "numberOfAttempts" => x => x.NumberOfAttempts.ToString().Contains(value), + "blockedAt" => x => x.BlockedAt.ToString().Contains(value), + "unblockedin" => x => x.UnblockedIn.ToString().Contains(value), + _ => x => x.IPAddress.ToString().Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "ipaddress" => x => x.IPAddress, + "numberofattempts" => x => x.NumberOfAttempts, + "blockedat" => x => x.BlockedAt, + "unblockedin" => x => x.UnblockedIn, + _ => x => x.IPAddress + }; + } + + public async Task UnblockIPAddress(AuditUserDetails auditUserDetails, string ipaddress, CancellationToken cancellationToken) + { + await _blockedIPsManagerRepository.UnBlockIP(auditUserDetails, ipaddress, cancellationToken); + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/Extensions/DoubleExtensions.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/Extensions/DoubleExtensions.cs new file mode 100644 index 0000000..1cd96e6 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/Extensions/DoubleExtensions.cs @@ -0,0 +1,9 @@ +namespace e_suite.Modules.BlockedIPsManager.Extensions; + +public static class DoubleExtensions +{ + public static int ToInteger(this double value) + { + return (int)value; + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/GlobalSuppressions.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/GlobalSuppressions.cs new file mode 100644 index 0000000..924306c --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "", Scope = "member", Target = "~M:e_suite.Modules.BlockedIPsManager.BlockedIPsManager.#ctor(e_suite.API.Common.repository.IBlockedIPsManagerRepository,eSuite.Core.Clock.IClock,Microsoft.Extensions.Configuration.IConfiguration)")] diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/IocRegistration.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/IocRegistration.cs new file mode 100644 index 0000000..0765dff --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.BlockedIPsManager.Repository; + +namespace e_suite.Modules.BlockedIPsManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/Repository/BlockedIPsManagerRepository.cs b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/Repository/BlockedIPsManagerRepository.cs new file mode 100644 index 0000000..046c626 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/Repository/BlockedIPsManagerRepository.cs @@ -0,0 +1,26 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using FailedAccessAttempt = e_suite.Database.Core.Tables.Sentinel.FailedAccessAttempt; + +namespace e_suite.Modules.BlockedIPsManager.Repository; + +public class BlockedIPsManagerRepository : RepositoryBase, IBlockedIPsManagerRepository +{ + public BlockedIPsManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetBlockedIPs(DateTimeOffset earliestAttemptTime) + { + return DatabaseDbContext.FailedAccessAttempts + .Where(x => x.AttemptedTime >= earliestAttemptTime); + } + + public async Task UnBlockIP(AuditUserDetails auditUserDetails, string ipAddress, CancellationToken cancellationToken) + { + var failedAccessAttempts = DatabaseDbContext.FailedAccessAttempts.Where(x => x.IPAddress == ipAddress); + DatabaseDbContext.FailedAccessAttempts.RemoveRange(failedAccessAttempts); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} diff --git a/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/e-suite.Modules.BlockedIPsManager.csproj b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/e-suite.Modules.BlockedIPsManager.csproj new file mode 100644 index 0000000..6d5be43 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/e-suite.Modules.BlockedIPsManager/e-suite.Modules.BlockedIPsManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.BlockedIPsManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Manager.BlockedIPs/nuget.config b/e-suite.Manager.BlockedIPs/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Manager.BlockedIPs/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.MessageProcessor/.dockerignore b/e-suite.MessageProcessor/.dockerignore new file mode 100644 index 0000000..bdca33b --- /dev/null +++ b/e-suite.MessageProcessor/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/e-suite.MessageProcessor/.gitattributes b/e-suite.MessageProcessor/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.MessageProcessor/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.MessageProcessor/.gitignore b/e-suite.MessageProcessor/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.MessageProcessor/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.MessageProcessor/.runsettings b/e-suite.MessageProcessor/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.MessageProcessor/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.MessageProcessor/README.md b/e-suite.MessageProcessor/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.MessageProcessor/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.MessageProcessor/azure-pipelines.yml b/e-suite.MessageProcessor/azure-pipelines.yml new file mode 100644 index 0000000..61c36cf --- /dev/null +++ b/e-suite.MessageProcessor/azure-pipelines.yml @@ -0,0 +1,106 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(postfix)$(branchName) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: ubuntu-latest # ubuntu-latest - set to windows-latest or another Windows vmImage for Windows builds + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + containerRegistry: esuite.azurecr.io + DOCKER_BUILDKIT: 1 + + imageName: 'e-suite.MessageProcessor' + + publishPath: $(Build.Repository.LocalPath)/build/e-suite.MessageProcessor + + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + branchName: '' + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}: + branchName: $[ replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-' ) ] + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}: + branchName: $[ replace(replace(variables['System.PullRequest.TargetBranch'], 'refs/heads/', ''), '/', '-' ) ] + + ${{ if eq(variables['branchName'], '') }}: + postfix: '' + ${{ else }}: + postfix: '-' + +steps: +- task: UseDotNet@2 + displayName: 'Set .net core version' + inputs: + version: '9.0.x' + +- task: DotNetCoreCLI@2 + displayName: 'Nuget Restore' + inputs: + command: 'restore' + feedsToUse: config + projects: '**/*.csproj' + nugetConfigPath: nuget.config + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--configuration $(buildConfiguration)' + displayName: 'dotnet build $(buildConfiguration)' + +- task: DotNetCoreCLI@2 + displayName: 'Run Tests' + inputs: + command: test + projects: '**/*Tests/*.csproj' + arguments: '--configuration $(buildConfiguration) --collect "Code coverage" --settings .runsettings' + +- task: DotNetCoreCLI@2 + displayName: 'Publish e-suite.MessageProcessor' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: publish + projects: 'e-suite.MessageProcessor/e-suite.MessageProcessor.csproj' + publishWebProjects: false + arguments: -c $(BuildConfiguration) -o build + zipAfterPublish: false + +- powershell: | + Write-Host "Show all folder content" + Get-ChildItem -Path $(publishPath)\*.* -Recurse -Force | % { $_.FullName } + errorActionPreference: continue + displayName: 'PowerShell Script List folder structure' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + continueOnError: true + +- task: Docker@2 + displayName: Build e-suite.MessageProcessor Image + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: build + repository: $(imageName) + buildContext: $(publishPath) + Dockerfile: $(publishPath)/Dockerfile.Azure + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) + +- task: Docker@2 + displayName: Push e-suite.MessageProcessor + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: push + repository: $(imageName) + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/DatabaseQueueHandlerUnitTests.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/DatabaseQueueHandlerUnitTests.cs new file mode 100644 index 0000000..4040589 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/DatabaseQueueHandlerUnitTests.cs @@ -0,0 +1,125 @@ +using System.Text; +using System.Text.Json; +using e_suite.API.Common; +using e_suite.MessageProcessor.Handlers; +using e_suite.Messaging.Common; +using e_suite.Messaging.Common.models; +using e_suite.Modules.UserManager; +using e_suite.Service.Sentinel; +using e_suite.UnitTestCore; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using RabbitMQ.Client.Events; + +namespace e_suite.MessageProcessor.UnitTests; + +[TestFixture] +public class DatabaseQueueHandlerUnitTests : TestBase +{ + protected Mock SentinelMaintenanceMock { get; set; } = null!; + protected Mock PerformanceMaintenanceMock { get; set; } = null!; + protected Mock UserManagerMaintenanceMock { get; set; } = null!; + protected Mock LoggerMock {get; set; } = null!; + protected DatabaseQueueHandler DatabaseQueueHandler { get; set; } = null!; + + [SetUp] + public override Task Setup() + { + SentinelMaintenanceMock = new Mock(); + PerformanceMaintenanceMock = new Mock(); + UserManagerMaintenanceMock = new Mock(); + LoggerMock = new Mock(); + _fakeClock = new FakeClock(); + + DatabaseQueueHandler = new DatabaseQueueHandler(SentinelMaintenanceMock.Object, PerformanceMaintenanceMock.Object, UserManagerMaintenanceMock.Object, _fakeClock, LoggerMock.Object); + + return base.Setup(); + } + + private byte[] ObjectToStream(T item) + { + var json = JsonSerializer.Serialize(item); + return Encoding.UTF8.GetBytes(json); + } + + [Test] + public async Task OnReceived_ClearOldSentinelData_CallsSentinelMaintenance() + { + //Arrange + var message = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldSentinelData + }; + + var body = ObjectToStream(message); + + var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body); + + //Act + await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs); + + //Assert + SentinelMaintenanceMock.Verify( x => x.ClearOldSentinelData(), Times.Once); + } + + [Test] + public async Task OnReceived_ClearOldPerformanceData_CallsPerformanceMaintenance() + { + //Arrange + var message = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldPerformanceData + }; + + var body = ObjectToStream(message); + + var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body); + + //Act + await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs); + + //Assert + PerformanceMaintenanceMock.Verify(x => x.ClearOldPerformanceData(), Times.Once); + } + + [Test] + public async Task OnReceived_ClearOldEmailActions_CallsUserManagerMaintenance() + { + //Arrange + var message = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldEmailActions + }; + + var body = ObjectToStream(message); + + var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body); + + //Act + await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs); + + //Assert + UserManagerMaintenanceMock.Verify(x => x.ClearOldEmailActions(), Times.Once); + } + + [Test] + public async Task OnReceived_ClearOldSingleUserGuids_CallsUserManagerMaintenance() + { + //Arrange + var message = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldSingleUserGuids + }; + + var body = ObjectToStream(message); + + var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body); + + //Act + await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs); + + //Assert + UserManagerMaintenanceMock.Verify(x => x.ClearOldSingleUserGuids(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/SigmaImportQueueHandlerUnitTests.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/SigmaImportQueueHandlerUnitTests.cs new file mode 100644 index 0000000..299112a --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/SigmaImportQueueHandlerUnitTests.cs @@ -0,0 +1,90 @@ +using System.Text; +using System.Text.Json; +using e_suite.API.Common; +using e_suite.MessageProcessor.Handlers; +using e_suite.Messaging.Common; +using e_suite.Messaging.Common.models; +using e_suite.Modules.UserManager; +using e_suite.Service.Sentinel; +using e_suite.UnitTestCore; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using RabbitMQ.Client.Events; + +namespace e_suite.MessageProcessor.UnitTests; + +[TestFixture] +public class SigmaImportQueueHandlerUnitTests : TestBase +{ + protected Mock SentinelMaintenanceMock { get; set; } = null!; + protected Mock PerformanceMaintenanceMock { get; set; } = null!; + protected Mock UserManagerMaintenanceMock { get; set; } = null!; + protected Mock SigmaImporterMock { get; set; } = null!; + protected Mock EFlowSyncMessageSenderMock { get; set; } = null!; + protected Mock LoggerMock { get; set; } = null!; + protected SigmaImportQueueHandler QueueHandler { get; set; } = null!; + + [SetUp] + public override Task Setup() + { + SentinelMaintenanceMock = new Mock(); + PerformanceMaintenanceMock = new Mock(); + UserManagerMaintenanceMock = new Mock(); + SigmaImporterMock = new Mock(); + LoggerMock = new Mock(); + EFlowSyncMessageSenderMock = new Mock(); + _fakeClock = new FakeClock(); + + QueueHandler = new SigmaImportQueueHandler(_fakeClock, LoggerMock.Object, SigmaImporterMock.Object, EFlowSyncMessageSenderMock.Object); + + return base.Setup(); + } + + private static byte[] ObjectToStream(T item) + { + var json = JsonSerializer.Serialize(item); + return Encoding.UTF8.GetBytes(json); + } + + [Test] + public async Task OnReceived_ImportGMGProfiles_CallsImportGMGProfiles() + { + //Arrange + var message = new SigmaImportMessage + { + MessageType = SigmaImportMessageTypes.ImportGMGProfiles + }; + + var body = ObjectToStream(message); + + var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body); + + //Act + await QueueHandler.OnReceived(MessageQueueNames.SigmaImport, eventArgs); + + //Assert + SigmaImporterMock.Verify(x => x.ImportGMGProfiles(), Times.Once); + } + + [Test] + public async Task OnReceived_ImportPrintSpecifications_CallsImportPrintSpecifications() + { + //Arrange + var message = new SigmaImportMessage + { + MessageType = SigmaImportMessageTypes.ImportPrintSpecifications + }; + + var body = ObjectToStream(message); + + var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body); + + //Act + await QueueHandler.OnReceived(MessageQueueNames.SigmaImport, eventArgs); + + //Assert + SigmaImporterMock.Verify(x => x.ImportPrintSpecifications(), Times.Once); + EFlowSyncMessageSenderMock.Verify( x => x.SyncEFlowPrinterCategories(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/e-suite.MessageProcessor.UnitTests.csproj b/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/e-suite.MessageProcessor.UnitTests.csproj new file mode 100644 index 0000000..30e2766 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor.UnitTests/e-suite.MessageProcessor.UnitTests.csproj @@ -0,0 +1,25 @@ + + + + net10.0 + e_suite.MessageProcessor.UnitTests + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor.sln b/e-suite.MessageProcessor/e-suite.MessageProcessor.sln new file mode 100644 index 0000000..19e891a --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.MessageProcessor", "e-suite.MessageProcessor\e-suite.MessageProcessor.csproj", "{650094BF-E48A-444D-9F2B-712E1B61CF94}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{29474971-57EA-493B-8EED-96E9F8E3281C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{C9422963-1449-42F8-AD9C-CE6DEA334E68}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.MessageProcessor.UnitTests", "e-suite.MessageProcessor.UnitTests\e-suite.MessageProcessor.UnitTests.csproj", "{70416999-7B8B-4DCA-B608-CC53779F8156}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{204CDE22-14BA-40E5-BB8A-1141E09AD999}" + ProjectSection(SolutionItems) = preProject + azure-pipelines.yml = azure-pipelines.yml + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {650094BF-E48A-444D-9F2B-712E1B61CF94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {650094BF-E48A-444D-9F2B-712E1B61CF94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {650094BF-E48A-444D-9F2B-712E1B61CF94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {650094BF-E48A-444D-9F2B-712E1B61CF94}.Release|Any CPU.Build.0 = Release|Any CPU + {70416999-7B8B-4DCA-B608-CC53779F8156}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70416999-7B8B-4DCA-B608-CC53779F8156}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70416999-7B8B-4DCA-B608-CC53779F8156}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70416999-7B8B-4DCA-B608-CC53779F8156}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C9422963-1449-42F8-AD9C-CE6DEA334E68} = {29474971-57EA-493B-8EED-96E9F8E3281C} + {70416999-7B8B-4DCA-B608-CC53779F8156} = {C9422963-1449-42F8-AD9C-CE6DEA334E68} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F3B919DB-EE68-4F4F-91AB-1EFC950272C2} + EndGlobalSection +EndGlobal diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/DependencyInjection/CoreRegistrationModule.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/DependencyInjection/CoreRegistrationModule.cs new file mode 100644 index 0000000..3c35d99 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/DependencyInjection/CoreRegistrationModule.cs @@ -0,0 +1,64 @@ +using Autofac; +using e_suite.Database.Core; +using e_suite.Database.SqlServer; +using e_suite.MessageProcessor.Handlers; +using e_suite.MessageProcessor.QueueProcessor; +using eSuite.Core.Clock; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.MessageProcessor.DependencyInjection; + +/// +/// Used as a the primary location for IOC type registration for e-suite. +/// +public class CoreRegistrationModule : Module +{ + /// + /// Use the builder to register all the types and interfaces that the API requires to operate properly. + /// + /// + protected override void Load(ContainerBuilder builder) + { + var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder.AddConsole()); + + builder.Register(x => loggerFactory.CreateLogger("e-Suite.MessageProcessor")).As().SingleInstance(); + + IClock clock = new UtcClock(); + builder.RegisterInstance(clock).As().SingleInstance(); + + builder.RegisterInstance(ESuiteDatabaseExtension.BuildConfiguration()).As().SingleInstance(); + //builder.RegisterInstance(ESuiteDatabaseExtension.CreateDatabase(clock).GetAwaiter().GetResult()).As(); + builder.Register(c => + { + return ESuiteDatabaseExtension.CreateDatabase(clock).GetAwaiter().GetResult(); + }) + .As() + .InstancePerLifetimeScope(); + + + builder.RegisterType().InstancePerLifetimeScope(); + builder.RegisterType().InstancePerLifetimeScope(); + builder.RegisterType().InstancePerLifetimeScope(); + builder.RegisterType().InstancePerLifetimeScope(); + + Service.Sentinel.IocRegistration.RegisterTypes(builder); + Service.Performance.IocRegistration.RegisterTypes(builder); + Modules.UserManager.IocRegistration.RegisterTypes(builder); + Messaging.Common.DependencyInjection.CoreRegistrationModule.Load(builder); + Modules.ExceptionLogManager.IocRegistration.RegisterTypes(builder); + Service.SigmaImporter.IocRegistration.RegisterTypes(builder); + Modules.GlossariesManager.IocRegistration.RegisterTypes(builder); + Modules.DomainManager.IocRegistration.RegisterTypes(builder); + Modules.CustomFieldsManager.IocRegistration.RegisterTypes(builder); + Service.CustomFieldValidation.IocRegistration.RegisterTypes(builder); + Modules.SequenceManager.IocRegistration.RegisterTypes(builder); + Modules.FormsManager.IocRegistration.RegisterTypes(builder); + Modules.SiteManager.IocRegistration.RegisterTypes(builder); + Modules.SpecificationManager.IocRegistration.RegisterTypes(builder); + Modules.OrganisationsManager.IocRegistration.RegisterTypes(builder); + Modules.DomainManager.IocRegistration.RegisterTypes(builder); + Modules.SSOManager.IocRegistration.RegisterTypes(builder); + Service.EFlowSync.IocRegistration.RegisterTypes(builder); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Dockerfile b/e-suite.MessageProcessor/e-suite.MessageProcessor/Dockerfile new file mode 100644 index 0000000..04784c4 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Dockerfile @@ -0,0 +1,23 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src +COPY ["nuget.config", "."] +COPY ["TestApp1/TestApp1.csproj", "TestApp1/"] +RUN dotnet restore "TestApp1/TestApp1.csproj" +COPY . . +WORKDIR "/src/TestApp1" +RUN dotnet build "TestApp1.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "TestApp1.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "eSuite.API.dll"] \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Dockerfile.Azure b/e-suite.MessageProcessor/e-suite.MessageProcessor/Dockerfile.Azure new file mode 100644 index 0000000..c0fccec --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Dockerfile.Azure @@ -0,0 +1,9 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 as base +ENV DOTNET_ENVIRONMENT=Development +WORKDIR /app +COPY . . +EXPOSE 80 +EXPOSE 443 +ENTRYPOINT ["dotnet", "e-suite.MessageProcessor.dll"] diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Extensions/ObjectExtensions.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..52ca6f4 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Extensions/ObjectExtensions.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace e_suite.MessageProcessor.Extensions; + +/// +/// +/// +public static class ObjectExtensions +{ + /// + /// Serialize the current object to Json + /// + /// + /// + public static string ToJson(this object value) + { + var options = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + NullValueHandling = NullValueHandling.Include + }; + return JsonConvert.SerializeObject(value, options); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/GlobalSuppressions.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/DatabaseQueueHandler.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/DatabaseQueueHandler.cs new file mode 100644 index 0000000..d23d7e0 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/DatabaseQueueHandler.cs @@ -0,0 +1,53 @@ +using e_suite.API.Common; +using RabbitMQ.Client.Events; +using e_suite.Messaging.Common.models; +using e_suite.Modules.UserManager; +using e_suite.Service.Sentinel; +using eSuite.Core.Clock; +using Microsoft.Extensions.Logging; + +namespace e_suite.MessageProcessor.Handlers; + +public class DatabaseQueueHandler : QueueHandlerBase +{ + private readonly ISentinelMaintenance _sentinelMaintenance; + private readonly IPerformanceMaintenance _performanceMaintenance; + private readonly IUserManagerMaintenance _userManagerMaintenance; + private readonly ILogger _logger; + private readonly IClock _clock; + + public DatabaseQueueHandler(ISentinelMaintenance sentinelMaintenance, IPerformanceMaintenance performanceMaintenance, IUserManagerMaintenance userManagerMaintenance, IClock clock, ILogger logger) + { + _clock = clock; + _sentinelMaintenance = sentinelMaintenance; + _performanceMaintenance = performanceMaintenance; + _userManagerMaintenance = userManagerMaintenance; + _logger = logger; + } + + public override async Task OnReceived(string queueName, BasicDeliverEventArgs basicDeliverEventArgs) + { + var maintenanceMessage = await TranslateMessage(basicDeliverEventArgs); + _logger.LogInformation("{DateTime}: {MessageType} message received.", _clock.GetNow, maintenanceMessage.MessageType); + switch (maintenanceMessage.MessageType) + { + case DatabaseMessageTypes.ClearOldSentinelData: + await _sentinelMaintenance.ClearOldSentinelData(); + break; + case DatabaseMessageTypes.ClearOldPerformanceData: + await _performanceMaintenance.ClearOldPerformanceData(); + break; + case DatabaseMessageTypes.ClearOldEmailActions: + await _userManagerMaintenance.ClearOldEmailActions(); + break; + case DatabaseMessageTypes.ClearOldSingleUserGuids: + await _userManagerMaintenance.ClearOldSingleUserGuids(); + break; + default: +#pragma warning disable CA2208 // Instantiate argument exceptions correctly + throw new ArgumentOutOfRangeException( nameof(maintenanceMessage.MessageType), maintenanceMessage.MessageType, "Unexpected message type"); +#pragma warning restore CA2208 // Instantiate argument exceptions correctly + } + _logger.LogInformation("{DateTime}: {MessageType} message processing finished.", _clock.GetNow, maintenanceMessage.MessageType); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/EFlowImportQueueHandler.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/EFlowImportQueueHandler.cs new file mode 100644 index 0000000..6314793 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/EFlowImportQueueHandler.cs @@ -0,0 +1,38 @@ +using e_suite.API.Common; +using e_suite.Messaging.Common.models; +using eSuite.Core.Clock; +using Microsoft.Extensions.Logging; +using RabbitMQ.Client.Events; + +namespace e_suite.MessageProcessor.Handlers; + +public class EFlowImportQueueHandler : QueueHandlerBase +{ + private readonly ILogger _logger; + private readonly IClock _clock; + private readonly IEFlowSync _eFlowSync; + + public EFlowImportQueueHandler(IClock clock, ILogger logger, IEFlowSync eFlowSync) + { + _clock = clock; + _logger = logger; + _eFlowSync = eFlowSync; + } + + public override async Task OnReceived(string queueName, BasicDeliverEventArgs basicDeliverEventArgs) + { + var message = await TranslateMessage(basicDeliverEventArgs); + _logger.LogInformation("{DateTime}: {MessageType} message received.", _clock.GetNow, message.MessageType); + switch (message.MessageType) + { + case EFlowSyncMessageTypes.PrinterCategorySync: + var fullMessage = await TranslateMessage(basicDeliverEventArgs); + await _eFlowSync.SyncEFlowPrinterCategories(fullMessage.Domains); + break; + default: + throw new ArgumentOutOfRangeException(nameof(basicDeliverEventArgs), message.MessageType, $"Unexpected message type : {message.MessageType}"); + } + + _logger.LogInformation("{DateTime}: {MessageType} message processing finished.", _clock.GetNow, message.MessageType); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/QueueHandlerBase.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/QueueHandlerBase.cs new file mode 100644 index 0000000..c91e4a8 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/QueueHandlerBase.cs @@ -0,0 +1,17 @@ +using System.Text.Json; +using CommunityToolkit.HighPerformance; +using RabbitMQ.Client.Events; + +namespace e_suite.MessageProcessor.Handlers; + +public abstract class QueueHandlerBase +{ + protected static async Task TranslateMessage(BasicDeliverEventArgs basicDeliverEventArgs) + { + var stream = basicDeliverEventArgs.Body.AsStream(); + var message = await JsonSerializer.DeserializeAsync(stream) ?? throw new NullReferenceException("Unable to deserialise message"); + return message; + } + + public abstract Task OnReceived(string queueName, BasicDeliverEventArgs basicDeliverEventArgs); +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/SigmaImportQueueHandler.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/SigmaImportQueueHandler.cs new file mode 100644 index 0000000..4daaca5 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Handlers/SigmaImportQueueHandler.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common; +using e_suite.Messaging.Common; +using e_suite.Messaging.Common.models; +using eSuite.Core.Clock; +using Microsoft.Extensions.Logging; +using RabbitMQ.Client.Events; + +namespace e_suite.MessageProcessor.Handlers; + +public class SigmaImportQueueHandler : QueueHandlerBase +{ + private readonly ISigmaImporter _sigmaImporter; + private readonly ILogger _logger; + private readonly IClock _clock; + private readonly IEFlowSyncMessageSender _eFlowSyncMessageSender; + + public SigmaImportQueueHandler(IClock clock, ILogger logger, ISigmaImporter sigmaImporter, IEFlowSyncMessageSender eFlowSyncMessageSender) + { + _clock = clock; + _logger = logger; + _sigmaImporter = sigmaImporter; + _eFlowSyncMessageSender = eFlowSyncMessageSender; + } + + public override async Task OnReceived(string queueName, BasicDeliverEventArgs basicDeliverEventArgs) + { + var message = await TranslateMessage(basicDeliverEventArgs); + _logger.LogInformation("{DateTime}: {MessageType} message received.", _clock.GetNow, message.MessageType); + switch (message.MessageType) + { + case SigmaImportMessageTypes.ImportGMGProfiles: + await _sigmaImporter.ImportGMGProfiles(); + break; + case SigmaImportMessageTypes.ImportPrintSpecifications: + await _sigmaImporter.ImportPrintSpecifications(); + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + break; + default: + throw new ArgumentOutOfRangeException(nameof(basicDeliverEventArgs), message.MessageType, $"Unexpected message type : {message.MessageType}"); + } + _logger.LogInformation("{DateTime}: {MessageType} message processing finished.", _clock.GetNow, message.MessageType); + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/Program.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/Program.cs new file mode 100644 index 0000000..f483db7 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/Program.cs @@ -0,0 +1,44 @@ +using Autofac; +using Autofac.Extensions.DependencyInjection; +using e_suite.MessageProcessor.DependencyInjection; +using e_suite.MessageProcessor.QueueProcessor; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +/*Console.WriteLine("Initialising"); + +var containerBuilder = new ContainerBuilder(); +var coreRegistrationModule = new CoreRegistrationModule(); +await coreRegistrationModule.Load(containerBuilder); +var container = containerBuilder.Build(); + +Console.WriteLine("Starting Message Processor"); +using var queueProcessor = container.Resolve(); + +Console.WriteLine("Waiting for messages."); +Console.WriteLine("Press [enter] to stop and exit."); +Console.ReadLine();*/ + +var hostBuilder = new HostBuilder() + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureContainer(builder => + { + builder.RegisterModule(new CoreRegistrationModule()); + } + ) + // Add configuration, logging, ... + .ConfigureServices((hostContext, services) => + { + // Add your services with dependency injection. + services + .AddLogging(loggerBuilder => + { + loggerBuilder.ClearProviders(); + loggerBuilder.AddConsole(); + }); + + services.AddHostedService(); + }); + +hostBuilder.Build().Run(); \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/QueueProcessor/QueueProcessor.cs b/e-suite.MessageProcessor/e-suite.MessageProcessor/QueueProcessor/QueueProcessor.cs new file mode 100644 index 0000000..434dd63 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/QueueProcessor/QueueProcessor.cs @@ -0,0 +1,118 @@ +using System.Net; +using System.Text; +using e_suite.API.Common.extensions; +using e_suite.MessageProcessor.Handlers; +using RabbitMQ.Client.Events; +using RabbitMQ.Client; +using e_suite.Messaging.Common; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using e_suite.MessageProcessor.Extensions; +using e_suite.API.Common; +using System.Collections; +using Autofac; + +namespace e_suite.MessageProcessor.QueueProcessor; + +public class QueueProcessorService : IHostedService +{ + private readonly ILifetimeScope _lifetimeScope; + private readonly IConnection _connection; + private readonly ILogger _logger; + private readonly IExceptionLogManager _exceptionLogManager; + + public QueueProcessorService(ILifetimeScope lifetimeScope, IConfiguration configuration, ILogger logger, IRabbitMqConnectionFactory connectionFactory, IExceptionLogManager exceptionLogManager) + { + _lifetimeScope = lifetimeScope; + _logger = logger; + _exceptionLogManager = exceptionLogManager; + + connectionFactory.HostName = configuration.GetConfigValue("RABBITMQ_HOSTNAME", "RabbitMQ:hostname", "localhost")!; + + if (!string.Equals(connectionFactory.HostName, "localhost", StringComparison.InvariantCultureIgnoreCase) + && !string.Equals(connectionFactory.HostName, "host.docker.internal", StringComparison.InvariantCultureIgnoreCase)) + { + connectionFactory.VirtualHost = configuration.GetConfigValue("RABBITMQ_VHOST", "RabbitMQ:vhost", "")!; + connectionFactory.UserName = configuration.GetConfigValue("RABBITMQ_USER", "RabbitMQ:user", "")!; + connectionFactory.Password = configuration.GetConfigValue("RABBITMQ_PASSWORD", "RabbitMQ:password", "")!; + } + + _connection = connectionFactory.CreateConnection(); + } + + private List Channels { get; } = []; + + public async Task StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Timed Background Service is starting."); + + Channels.Add(await ListenForMessagesOnQueue(_connection, MessageQueueNames.Database)); + Channels.Add(await ListenForMessagesOnQueue(_connection, MessageQueueNames.SigmaImport)); + Channels.Add(await ListenForMessagesOnQueue(_connection, MessageQueueNames.EFlowSync)); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Timed Background Service is stopping."); + + foreach (var channel in Channels) + channel.Dispose(); + + _connection.Dispose(); + + return Task.CompletedTask; + } + + + public async Task ListenForMessagesOnQueue(IConnection connection, string queueName) where T : QueueHandlerBase + { + var channel = await connection.CreateChannelAsync(); + await channel.QueueDeclareAsync(queue: queueName, + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + var consumer1 = new AsyncEventingBasicConsumer(channel); + consumer1.ReceivedAsync += async (sender, ea) => + { + if (sender is not AsyncEventingBasicConsumer basicConsumer) + throw new NullReferenceException("channel cannot be null here!"); + try + { + await basicConsumer.Channel.BasicAckAsync(ea.DeliveryTag, false); + _logger.LogInformation("Message Acknowledged"); + + await using var messageLifetimeScope = _lifetimeScope.BeginLifetimeScope(); + var queueHandler = messageLifetimeScope.Resolve(); + await queueHandler.OnReceived(basicConsumer.Channel.CurrentQueue!, ea); + } + catch (Exception ex) + { + _logger.LogError("Error: {Message}", ex.Message); + if (ea.Redelivered) + { + var supportingData = new + { + ea.BasicProperties, + ea.Body, + ea.ConsumerTag, + ea.DeliveryTag, + ea.Exchange, + ea.RoutingKey + }.ToJson(); + + await _exceptionLogManager.LogException(ex, "e-suite.MessageProcessor", supportingData, CancellationToken.None); + await basicConsumer.Channel.BasicAckAsync(ea.DeliveryTag, false); + return; + } + await basicConsumer.Channel.BasicNackAsync(ea.DeliveryTag, false, true); + } + }; + await channel.BasicConsumeAsync(queue: queueName, + autoAck: false, + consumer: consumer1); + + return channel; + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.Development.json b/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.Development.json new file mode 100644 index 0000000..bd52181 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.Development.json @@ -0,0 +1,5 @@ +{ + "RabbitMQ": { + "hostname": "localhost" + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.Production.json b/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.Production.json new file mode 100644 index 0000000..bd52181 --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.Production.json @@ -0,0 +1,5 @@ +{ + "RabbitMQ": { + "hostname": "localhost" + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.json b/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.json new file mode 100644 index 0000000..2b6655d --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/appsettings.json @@ -0,0 +1,32 @@ +{ + "RabbitMQ": { + "hostname": "localhost" + }, + "SigmaFileBrowser": { + "Server": "172.27.17.228", + "Database": "external_crom", + "UserID": "cdawson", + "Password": "D'9[d38u$w6>J=B/Ac}HVF" + }, + "SigmaAirlock": { + "Server": "172.27.18.45", + "Database": "airlock", + "UserID": "cdawson", + "Password": "vH#5@Ubz.9'aPhEWBRf!dY" + }, + "SigmaFTPU": { + "Server": "172.27.18.63", + "Database": "ftpu", + "UserID": "cdawson", + "Password": "D'9[d38u$w6>J=B/Ac}HVF" + }, + "Sigma": { + "Server": "172.27.18.22", + "Database": "si6ma", + "UserID": "cdawson", + "Password": "D'9[d38u$w6>J=B/Ac}HVF" + }, + "EflowAPI": { + "Server": "https://sunrise-test-api-we.azurewebsites.net/" + } +} \ No newline at end of file diff --git a/e-suite.MessageProcessor/e-suite.MessageProcessor/e-suite.MessageProcessor.csproj b/e-suite.MessageProcessor/e-suite.MessageProcessor/e-suite.MessageProcessor.csproj new file mode 100644 index 0000000..e36fa6a --- /dev/null +++ b/e-suite.MessageProcessor/e-suite.MessageProcessor/e-suite.MessageProcessor.csproj @@ -0,0 +1,64 @@ + + + + Exe + net10.0 + e_suite.MessageProcessor + enable + enable + + + + + + + + + + + Always + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/e-suite.MessageProcessor/nuget.config b/e-suite.MessageProcessor/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.MessageProcessor/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Messaging.Common/.gitattributes b/e-suite.Messaging.Common/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Messaging.Common/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Messaging.Common/.gitignore b/e-suite.Messaging.Common/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Messaging.Common/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Messaging.Common/.runsettings b/e-suite.Messaging.Common/.runsettings new file mode 100644 index 0000000..e0fd691 --- /dev/null +++ b/e-suite.Messaging.Common/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Messaging.Common/README.md b/e-suite.Messaging.Common/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Messaging.Common/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Messaging.Common/azure-pipelinse.yml b/e-suite.Messaging.Common/azure-pipelinse.yml new file mode 100644 index 0000000..57b8e51 --- /dev/null +++ b/e-suite.Messaging.Common/azure-pipelinse.yml @@ -0,0 +1,81 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Messaging.Common/e-suite.Messaging.Common.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/DatabaseMessageSenderUnitTests.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/DatabaseMessageSenderUnitTests.cs new file mode 100644 index 0000000..cfa1adb --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/DatabaseMessageSenderUnitTests.cs @@ -0,0 +1,73 @@ +using e_suite.Messaging.Common.models; +using e_suite.Messaging.Common.UnitTests.Helpers; +using NUnit.Framework; + +namespace e_suite.Messaging.Common.UnitTests; + +[TestFixture] +public class DatabaseMessageSenderUnitTests : DatabaseMessageSenderTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [TearDown] + public override async Task TearDown() + { + await base.TearDown(); + } + + [Test] + public void NewDatabaseMessageSender_WhenCreated_DoesNotThrowException() + { + Assert.That(DatabaseMessageSender, Is.Not.Null); + } + + private const string BasicMessage = "{{\"MessageType\":{0}}}"; + + [Test] + public void PostClearOldSentinelData_WhenCalled_SendsCorrectMessage() + { + //Arrange + // Act + DatabaseMessageSender.PostClearOldSentinelData(); + + // Assert + Assert.That(Body, Is.EqualTo(string.Format(BasicMessage, (int)DatabaseMessageTypes.ClearOldSentinelData))); + } + + [Test] + public void PostClearOldPerformanceData_WhenCalled_SendsCorrectMessage() + { + //Arrange + //Act + DatabaseMessageSender.PostClearOldPerformanceData(); + + //Assert + Assert.That(Body, Is.EqualTo(string.Format(BasicMessage, (int)DatabaseMessageTypes.ClearOldPerformanceData))); + } + + [Test] + public void PostClearOldEmailActions_WhenCalled_SendsCorrectMessage() + { + //Arrange + //Act + DatabaseMessageSender.PostClearOldEmailActions(); + + //Assert + Assert.That(Body, Is.EqualTo(string.Format(BasicMessage, (int)DatabaseMessageTypes.ClearOldEmailActions))); + } + + [Test] + public void PostClearOldSingleUserGuids_WhenCalled_SendsCorrectMessage() + { + //Arrange + //Act + DatabaseMessageSender.PostClearOldSingleUserGuids(); + + //Assert + Assert.That(Body, Is.EqualTo(string.Format(BasicMessage, (int)DatabaseMessageTypes.ClearOldSingleUserGuids))); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/Helpers/DatabaseMessageSenderUnitTestsTestBase.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/Helpers/DatabaseMessageSenderUnitTestsTestBase.cs new file mode 100644 index 0000000..09aa417 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/Helpers/DatabaseMessageSenderUnitTestsTestBase.cs @@ -0,0 +1,97 @@ +using e_suite.UnitTestCore; +using Moq; +using RabbitMQ.Client; +using System.Text; + +namespace e_suite.Messaging.Common.UnitTests.Helpers; + +public class DatabaseMessageSenderTestBase : TestBase +{ + protected Mock Channel { get; set; } = new Mock(); + protected string? Body = null; + + protected DatabaseMessageSender DatabaseMessageSender { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + Channel.Setup(x => x.BasicPublishAsync( + string.Empty, + MessageQueueNames.Database, + It.IsAny(), + It.IsAny(), + It.IsAny>(), + It.IsAny() + )) + .Returns(ValueTask.CompletedTask) + .Callback, CancellationToken>( + (exchange, routingKey, mandatory, basicProperties, body, cancellationToken) => + { + Body = Encoding.UTF8.GetString(body.ToArray()); + }); + + var connection = new Mock(); + connection.Setup(x => x.CreateChannelAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(Channel.Object); + + var connectionFactoryMock = new Mock(); + connectionFactoryMock.Setup(x => x.CreateConnection()).Returns(connection.Object); + + DatabaseMessageSender = new DatabaseMessageSender(_configuration, connectionFactoryMock.Object); + } + + public virtual Task TearDown() + { + DatabaseMessageSender.Dispose(); + return Task.CompletedTask; + } +} + +public class SigmaImportMessageSenderTestBase : TestBase +{ + protected Mock Channel { get; set; } = new Mock(); + protected string? Body = null; + + protected SigmaImportMessageSender SigmaImportMessageSender { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + Channel.Setup(x => x.BasicPublishAsync( + string.Empty, + MessageQueueNames.SigmaImport, + It.IsAny(), + It.IsAny(), + It.IsAny>(), + It.IsAny())) + .Returns(ValueTask.CompletedTask) + .Callback, CancellationToken>(( + exchange, + routineKey, + mandatory, + basicProperties, + body, + cancellationToken + ) => + { + Body = Encoding.UTF8.GetString(body.ToArray()); + }); + + var connection = new Mock(); + connection.Setup(x => x.CreateChannelAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(Channel.Object); + + var connectionFactoryMock = new Mock(); + connectionFactoryMock.Setup(x => x.CreateConnection()).Returns(connection.Object); + + SigmaImportMessageSender = new SigmaImportMessageSender(_configuration, connectionFactoryMock.Object); + } + + public virtual Task TearDown() + { + SigmaImportMessageSender.Dispose(); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/SigmaImportMessageSenderUnitTests.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/SigmaImportMessageSenderUnitTests.cs new file mode 100644 index 0000000..0f7ebe5 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/SigmaImportMessageSenderUnitTests.cs @@ -0,0 +1,51 @@ +using e_suite.Messaging.Common.models; +using e_suite.Messaging.Common.UnitTests.Helpers; +using NUnit.Framework; + +namespace e_suite.Messaging.Common.UnitTests; + +[TestFixture] +public class SigmaImportMessageSenderUnitTests : SigmaImportMessageSenderTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [TearDown] + public override async Task TearDown() + { + await base.TearDown(); + } + + [Test] + public void NewDatabaseMessageSender_WhenCreated_DoesNotThrowException() + { + Assert.That(SigmaImportMessageSender, Is.Not.Null); + } + + private const string BasicMessage = "{{\"MessageType\":{0}}}"; + + [Test] + public void PostImportGMGProfiles_WhenCalled_SendsCorrectMessage() + { + //Arrange + // Act + SigmaImportMessageSender.PostImportGMGProfiles(); + + // Assert + Assert.That(Body, Is.EqualTo(string.Format(BasicMessage, (int)SigmaImportMessageTypes.ImportGMGProfiles))); + } + + [Test] + public void PostImportPrintSpecifications_WhenCalled_SendsCorrectMessage() + { + //Arrange + // Act + SigmaImportMessageSender.PostImportPrintSpecifications(); + + // Assert + Assert.That(Body, Is.EqualTo(string.Format(BasicMessage, (int)SigmaImportMessageTypes.ImportPrintSpecifications))); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/e-suite.Messaging.Common.UnitTests.csproj b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/e-suite.Messaging.Common.UnitTests.csproj new file mode 100644 index 0000000..fad2d1a --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common.UnitTests/e-suite.Messaging.Common.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + e_suite.Messaging.Common.UnitTests + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common.sln b/e-suite.Messaging.Common/e-suite.Messaging.Common.sln new file mode 100644 index 0000000..45dab27 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Messaging.Common", "e-suite.Messaging.Common\e-suite.Messaging.Common.csproj", "{F0BE3F54-DE9D-450A-80E8-B47D670F2EE8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{F66288FD-4E9D-49C0-8510-BF140B3D22AC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{62B9A608-74C7-4072-9E21-378F2DE9B05B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Messaging.Common.UnitTests", "e-suite.Messaging.Common.UnitTests\e-suite.Messaging.Common.UnitTests.csproj", "{E1C69D7C-846B-421B-87D9-FC30397576A8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F0BE3F54-DE9D-450A-80E8-B47D670F2EE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0BE3F54-DE9D-450A-80E8-B47D670F2EE8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0BE3F54-DE9D-450A-80E8-B47D670F2EE8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0BE3F54-DE9D-450A-80E8-B47D670F2EE8}.Release|Any CPU.Build.0 = Release|Any CPU + {E1C69D7C-846B-421B-87D9-FC30397576A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1C69D7C-846B-421B-87D9-FC30397576A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1C69D7C-846B-421B-87D9-FC30397576A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1C69D7C-846B-421B-87D9-FC30397576A8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {62B9A608-74C7-4072-9E21-378F2DE9B05B} = {F66288FD-4E9D-49C0-8510-BF140B3D22AC} + {E1C69D7C-846B-421B-87D9-FC30397576A8} = {62B9A608-74C7-4072-9E21-378F2DE9B05B} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6F222E1A-C88E-44CB-B1CC-2F21BCC297B0} + EndGlobalSection +EndGlobal diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common.v3.ncrunchsolution b/e-suite.Messaging.Common/e-suite.Messaging.Common.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/DatabaseMessageSender.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/DatabaseMessageSender.cs new file mode 100644 index 0000000..bf960ce --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/DatabaseMessageSender.cs @@ -0,0 +1,64 @@ +using e_suite.Messaging.Common.models; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Messaging.Common; + +public class DatabaseMessageSender : MessageSenderBase, IDatabaseMessageSender +{ + public DatabaseMessageSender(IConfiguration configuration, IRabbitMqConnectionFactory connectionFactory) : base(configuration, connectionFactory, MessageQueueNames.Database) + { + + } + + public void PostClearOldSentinelData() + { + var maintenanceMessage = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldSentinelData + }; + + Task.Run(async () => + { + await PostMessage(maintenanceMessage); + }).Wait(); + } + + public void PostClearOldPerformanceData() + { + var maintenanceMessage = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldPerformanceData + }; + + Task.Run(async () => + { + await PostMessage(maintenanceMessage); + }).Wait(); + } + + public void PostClearOldEmailActions() + { + var maintenanceMessage = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldEmailActions + }; + + Task.Run(async () => + { + await PostMessage(maintenanceMessage); + }).Wait(); + } + + public void PostClearOldSingleUserGuids() + { + var maintenanceMessage = new DatabaseMessage + { + MessageType = DatabaseMessageTypes.ClearOldSingleUserGuids + }; + + Task.Run(async () => + { + await PostMessage(maintenanceMessage); + }).Wait(); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/DependencyInjection/CoreRegistrationModule.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/DependencyInjection/CoreRegistrationModule.cs new file mode 100644 index 0000000..d8e137e --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/DependencyInjection/CoreRegistrationModule.cs @@ -0,0 +1,23 @@ +using Autofac; +using RabbitMQ.Client; + +namespace e_suite.Messaging.Common.DependencyInjection; + +/// +/// Used as a the primary location for IOC type registration for e-suite. +/// +public static class CoreRegistrationModule +{ + /// + /// Use the builder to register all the types and interfaces that the API requires to operate properly. + /// + /// + public static void Load(ContainerBuilder builder) + { + builder.RegisterType(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/EFlowSyncMessageSender.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/EFlowSyncMessageSender.cs new file mode 100644 index 0000000..aa74cf6 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/EFlowSyncMessageSender.cs @@ -0,0 +1,33 @@ +using e_suite.Messaging.Common.models; +using eSuite.Core.Miscellaneous; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Messaging.Common; + +public class EFlowSyncMessageSender : MessageSenderBase, IEFlowSyncMessageSender +{ + public EFlowSyncMessageSender(IConfiguration configuration, IRabbitMqConnectionFactory connectionFactory) : base( + configuration, connectionFactory, MessageQueueNames.EFlowSync) + { + + } + + public void SyncEFlowPrinterCategories() + { + SyncEFlowPrinterCategories([]); + } + + public void SyncEFlowPrinterCategories(List domains) + { + var message = new EFlowPrinterCategorySyncMessage + { + MessageType = EFlowSyncMessageTypes.PrinterCategorySync, + Domains = domains + }; + + Task.Run(async () => + { + await PostMessage(message); + }).Wait(); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/Exceptions/FailedToConnectException.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/Exceptions/FailedToConnectException.cs new file mode 100644 index 0000000..52da3bd --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/Exceptions/FailedToConnectException.cs @@ -0,0 +1,13 @@ +namespace e_suite.Messaging.Common.Exceptions; + +public class FailedToConnectException : Exception +{ + public FailedToConnectException(string? message):base(message) + { + } + + public FailedToConnectException(string? message, Exception? innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/GlobalSuppressions.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/GlobalSuppressions.cs new file mode 100644 index 0000000..9633a17 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/IDatabaseMessageSender.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/IDatabaseMessageSender.cs new file mode 100644 index 0000000..b6b0f88 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/IDatabaseMessageSender.cs @@ -0,0 +1,12 @@ +namespace e_suite.Messaging.Common; + +public interface IDatabaseMessageSender +{ + void PostClearOldSentinelData(); + + void PostClearOldPerformanceData(); + + void PostClearOldEmailActions(); + + void PostClearOldSingleUserGuids(); +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/IEFlowSyncMessageSender.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/IEFlowSyncMessageSender.cs new file mode 100644 index 0000000..a779a70 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/IEFlowSyncMessageSender.cs @@ -0,0 +1,9 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.Messaging.Common; + +public interface IEFlowSyncMessageSender +{ + void SyncEFlowPrinterCategories(); + void SyncEFlowPrinterCategories(List domains); +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/IRabbitMqConnectionFactory.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/IRabbitMqConnectionFactory.cs new file mode 100644 index 0000000..05edd79 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/IRabbitMqConnectionFactory.cs @@ -0,0 +1,13 @@ +using RabbitMQ.Client; + +namespace e_suite.Messaging.Common; + +public interface IRabbitMqConnectionFactory +{ + public string HostName { get; set; } + public string VirtualHost { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + + IConnection CreateConnection(); +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/ISigmaImportMessageSender.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/ISigmaImportMessageSender.cs new file mode 100644 index 0000000..b87bb94 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/ISigmaImportMessageSender.cs @@ -0,0 +1,8 @@ +namespace e_suite.Messaging.Common; + +public interface ISigmaImportMessageSender +{ + void PostImportGMGProfiles(); + + void PostImportPrintSpecifications(); +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/MessageQueueNames.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/MessageQueueNames.cs new file mode 100644 index 0000000..3a33343 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/MessageQueueNames.cs @@ -0,0 +1,8 @@ +namespace e_suite.Messaging.Common; + +public static class MessageQueueNames +{ + public const string Database = "database"; + public const string SigmaImport = "sigmaImport"; + public const string EFlowSync = "EFlowSync"; +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/MessageSenderBase.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/MessageSenderBase.cs new file mode 100644 index 0000000..0109df8 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/MessageSenderBase.cs @@ -0,0 +1,75 @@ +using System.Text; +using System.Text.Json; +using e_suite.API.Common.extensions; +using Microsoft.Extensions.Configuration; +using RabbitMQ.Client; + +namespace e_suite.Messaging.Common; + +public abstract class MessageSenderBase : IDisposable +{ + private readonly IConfiguration _configuration; + private readonly IRabbitMqConnectionFactory _connectionFactory; + private IConnection? _connection = null; + private IChannel? _channel = null; + private readonly string _messageQueueName; + + public async Task GetChannel() + { + if (_channel == null) + { + _connectionFactory.HostName = _configuration.GetConfigValue("RABBITMQ_HOSTNAME", "RabbitMQ:hostname", "localhost")!; + + if (!string.Equals(_connectionFactory.HostName, "localhost", StringComparison.InvariantCultureIgnoreCase) + && !string.Equals(_connectionFactory.HostName, "host.docker.internal", StringComparison.InvariantCultureIgnoreCase)) + { + _connectionFactory.VirtualHost = _configuration.GetConfigValue("RABBITMQ_VHOST", "RabbitMQ:vhost", "")!; + _connectionFactory.UserName = _configuration.GetConfigValue("RABBITMQ_USER", "RabbitMQ:user", "")!; + _connectionFactory.Password = _configuration.GetConfigValue("RABBITMQ_PASSWORD", "RabbitMQ:password", "")!; + } + + _connection = _connectionFactory.CreateConnection(); + _channel = await _connection.CreateChannelAsync(); + + await _channel.QueueDeclareAsync(queue: _messageQueueName, + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + } + + return _channel; + } + + protected MessageSenderBase(IConfiguration configuration, IRabbitMqConnectionFactory connectionFactory, string messageQueueName) + { + ArgumentNullException.ThrowIfNull(configuration, nameof(configuration)); + _configuration = configuration; + _connectionFactory = connectionFactory; + _messageQueueName = messageQueueName; + } + + public virtual void Dispose() + { + GC.SuppressFinalize(this); + if (_channel != null) + { + _channel.Dispose(); + _connection!.Dispose(); + } + } + + protected async Task PostMessage(T message) + { + var json = JsonSerializer.Serialize(message); + var body = Encoding.UTF8.GetBytes(json); + + var channel = await GetChannel(); + await channel.BasicPublishAsync( + exchange: string.Empty, + routingKey: _messageQueueName, + mandatory: false, + basicProperties: new BasicProperties(), + body: body); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/RabbitMqConnectionFactory.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/RabbitMqConnectionFactory.cs new file mode 100644 index 0000000..2408f5f --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/RabbitMqConnectionFactory.cs @@ -0,0 +1,51 @@ +using e_suite.Messaging.Common.Exceptions; +using RabbitMQ.Client; + +namespace e_suite.Messaging.Common; + +/// +/// This is a wrapper around the RabbitMQ ConnectionFactory to allow the calls to be mocked giving access to unit testing. +/// +public class RabbitMqConnectionFactory : IRabbitMqConnectionFactory +{ + private readonly ConnectionFactory _connectionFactory; + + public RabbitMqConnectionFactory() + { + _connectionFactory = new ConnectionFactory(); + } + + public string HostName { + get => _connectionFactory.HostName; + set => _connectionFactory.HostName = value; + } + + public string VirtualHost + { + get => _connectionFactory.VirtualHost; + set => _connectionFactory.VirtualHost = value; + } + + public string UserName + { + get => _connectionFactory.UserName; + set => _connectionFactory.UserName = value; + } + + public string Password + { + get => _connectionFactory.Password; + set => _connectionFactory.Password = value; + } + public IConnection CreateConnection() + { + try + { + return _connectionFactory.CreateConnectionAsync().GetAwaiter().GetResult(); + } + catch (Exception ex) + { + throw new FailedToConnectException($"Failed to connect to RabbitMq as HostName: {VirtualHost}, VirtualHost: {VirtualHost} Username: {UserName}", ex ); + } + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/SigmaImportMessageSender.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/SigmaImportMessageSender.cs new file mode 100644 index 0000000..9170fed --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/SigmaImportMessageSender.cs @@ -0,0 +1,39 @@ +using e_suite.Messaging.Common.models; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Messaging.Common; + +public class SigmaImportMessageSender : MessageSenderBase, ISigmaImportMessageSender +{ + public SigmaImportMessageSender(IConfiguration configuration, IRabbitMqConnectionFactory connectionFactory) : base( + configuration, connectionFactory, MessageQueueNames.SigmaImport) + { + + } + + public void PostImportGMGProfiles() + { + var message = new SigmaImportMessage + { + MessageType = SigmaImportMessageTypes.ImportGMGProfiles + }; + + Task.Run(async () => + { + await PostMessage(message); + }).Wait(); + } + + public void PostImportPrintSpecifications() + { + var message = new SigmaImportMessage + { + MessageType = SigmaImportMessageTypes.ImportPrintSpecifications + }; + + Task.Run(async () => + { + await PostMessage(message); + }).Wait(); + } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/e-suite.Messaging.Common.csproj b/e-suite.Messaging.Common/e-suite.Messaging.Common/e-suite.Messaging.Common.csproj new file mode 100644 index 0000000..bf36f30 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/e-suite.Messaging.Common.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + e_suite.Messaging.Common + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/models/DatabaseMessage.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/DatabaseMessage.cs new file mode 100644 index 0000000..ea2300a --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/DatabaseMessage.cs @@ -0,0 +1,6 @@ +namespace e_suite.Messaging.Common.models; + +public class DatabaseMessage +{ + public DatabaseMessageTypes MessageType { get; set; } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/models/DatabaseMessageTypes.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/DatabaseMessageTypes.cs new file mode 100644 index 0000000..77f0839 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/DatabaseMessageTypes.cs @@ -0,0 +1,9 @@ +namespace e_suite.Messaging.Common.models; + +public enum DatabaseMessageTypes +{ + ClearOldSentinelData = 1, + ClearOldPerformanceData = 2, + ClearOldEmailActions = 3, + ClearOldSingleUserGuids = 4 +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/models/EFlowPrinterCategorySyncMessage.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/EFlowPrinterCategorySyncMessage.cs new file mode 100644 index 0000000..cbe6f65 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/EFlowPrinterCategorySyncMessage.cs @@ -0,0 +1,13 @@ +using eSuite.Core.Miscellaneous; + +namespace e_suite.Messaging.Common.models; + +public class EFlowSyncMessage +{ + public EFlowSyncMessageTypes MessageType { get; set; } +} + +public class EFlowPrinterCategorySyncMessage : EFlowSyncMessage +{ + public List Domains { get; set; } = []; +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/models/EFlowSyncMessageTypes.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/EFlowSyncMessageTypes.cs new file mode 100644 index 0000000..a215468 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/EFlowSyncMessageTypes.cs @@ -0,0 +1,6 @@ +namespace e_suite.Messaging.Common.models; + +public enum EFlowSyncMessageTypes +{ + PrinterCategorySync = 1 +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/models/SigmaImportMessage.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/SigmaImportMessage.cs new file mode 100644 index 0000000..9a78758 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/SigmaImportMessage.cs @@ -0,0 +1,6 @@ +namespace e_suite.Messaging.Common.models; + +public class SigmaImportMessage +{ + public SigmaImportMessageTypes MessageType { get; set; } +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/e-suite.Messaging.Common/models/SigmaImportMessageTypes.cs b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/SigmaImportMessageTypes.cs new file mode 100644 index 0000000..e6c6ae1 --- /dev/null +++ b/e-suite.Messaging.Common/e-suite.Messaging.Common/models/SigmaImportMessageTypes.cs @@ -0,0 +1,7 @@ +namespace e_suite.Messaging.Common.models; + +public enum SigmaImportMessageTypes +{ + ImportGMGProfiles = 1, + ImportPrintSpecifications = 2 +} \ No newline at end of file diff --git a/e-suite.Messaging.Common/nuget.config b/e-suite.Messaging.Common/nuget.config new file mode 100644 index 0000000..cc8183d --- /dev/null +++ b/e-suite.Messaging.Common/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/.gitattributes b/e-suite.Modules.AuditLog/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.AuditLog/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/.gitignore b/e-suite.Modules.AuditLog/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.AuditLog/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.AuditLog/.runsettings b/e-suite.Modules.AuditLog/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Modules.AuditLog/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/AuditLog.UnitTests/AuditLog.UnitTests.csproj b/e-suite.Modules.AuditLog/AuditLog.UnitTests/AuditLog.UnitTests.csproj new file mode 100644 index 0000000..2aa797f --- /dev/null +++ b/e-suite.Modules.AuditLog/AuditLog.UnitTests/AuditLog.UnitTests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.AuditLog/AuditLog.UnitTests/GetAuditLogEntriesUnitTests.cs b/e-suite.Modules.AuditLog/AuditLog.UnitTests/GetAuditLogEntriesUnitTests.cs new file mode 100644 index 0000000..7b11ea6 --- /dev/null +++ b/e-suite.Modules.AuditLog/AuditLog.UnitTests/GetAuditLogEntriesUnitTests.cs @@ -0,0 +1,206 @@ +using AuditLog.UnitTests.Helpers; +using e_suite.Database.Audit.Tables.Audit; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace AuditLog.UnitTests; + +[TestFixture] +public class GetAuditLogEntriesUnitTests : AuditLogTestBase +{ + + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetAuditLogEntries_WithNoExtraFilters_ReturnsPagingStructure() + { + //Arrange + var paging = new Paging(); + + //Act + var result = await AuditLog.GetAuditLogEntries(paging, null, false, default); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(0)); + Assert.That(result.Count, Is.EqualTo(0)); + Assert.That(result.Data.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task GetAuditLogEntries_WhenDataAvailable_ReturnItem() + { + //Arrange + var auditEntry = new AuditEntry + { + AuditLogId = 1, + DisplayName = "Test DisplayName", + EntityName = "TestEntiryName", + IsPrimary = true, + Id = 1, + PrimaryKey = "{{ \"id\": 1 }}", + AuditLog = new AuditDetail + { + Id = 10, + Comment = "Testing", + DateTime = new DateTimeOffset(2023, 06, 15, 23, 56, 37, TimeSpan.Zero), + UserDisplayName = "Testy McTester", + UserId = 666, + Fields = "", + Type = "Add" + } + + }; + + AuditLogRepository.AuditEntries.Add(auditEntry); + + + var paging = new Paging(); + + //Act + var result = await AuditLog.GetAuditLogEntries(paging, null, false, default); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(1)); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + } + + [Test] + public async Task GetAuditLogEntries_WhenlogEntry_DecodesToAuditParamsCorrectly() + { + //Arrange + var auditEntry = new AuditEntry + { + AuditLogId = 1, + DisplayName = "Test DisplayName", + EntityName = "TestEntiryName", + IsPrimary = true, + Id = 1, + PrimaryKey = "{{ \"id\": 1 }}", + AuditLog = new AuditDetail + { + Id = 10, + Comment = "Testing", + DateTime = new DateTimeOffset(2023, 06, 15, 23, 56, 37, TimeSpan.Zero), + UserDisplayName = "Testy McTester", + UserId = 666, + Fields = "", + Type = "Add" + } + + }; + + AuditLogRepository.AuditEntries.Add(auditEntry); + + var logEntry = "ewogICJlbnRpdHlOYW1lIjoiVGVzdEVudGl0eSIsCiAgInByaW1hcnlLZXkiOiJ7aWQ6MTAxfSIKfQ=="; + + var paging = new Paging(); + + //Act + var result = await AuditLog.GetAuditLogEntries(paging, logEntry, false, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(AuditLogRepository.AuditParams, Is.Not.Null); + Assert.That(AuditLogRepository.AuditParams!.EntityName, Is.EqualTo("TestEntity")); + Assert.That(AuditLogRepository.AuditParams.PrimaryKey, Is.EqualTo("{id:101}")); + }); + } + + [Test] + public async Task GetAuditLogEntries_WhenAuditEntityHasDisplayName_DisplayNameIsSetIsEntityDisplayname() + { + //Arrange + var auditEntry = new AuditEntry + { + AuditLogId = 1, + DisplayName = "Test DisplayName", + EntityName = "AuditLog.UnitTests.TestEntity", + IsPrimary = true, + Id = 1, + PrimaryKey = "{{ \"id\": 1 }}", + AuditLog = new AuditDetail + { + Id = 10, + Comment = "Testing", + DateTime = new DateTimeOffset(2023, 06, 15, 23, 56, 37, TimeSpan.Zero), + UserDisplayName = "Testy McTester", + UserId = 666, + Fields = "", + Type = "Add" + } + + }; + + AuditLogRepository.AuditEntries.Add(auditEntry); + + var logEntry = "ewogICJlbnRpdHlOYW1lIjoiVGVzdEVudGl0eSIsCiAgInByaW1hcnlLZXkiOiJ7aWQ6MTAxfSIKfQ=="; + + var paging = new Paging(); + + //Act + var result = await AuditLog.GetAuditLogEntries(paging, logEntry, false, default); + + //Assert + var actualResult = result.Data.FirstOrDefault(); + Assert.Multiple(() => + { + Assert.That(actualResult, Is.Not.Null); + Assert.That(actualResult!.EntityDisplayName, Is.EqualTo("Test display name")); + }); + } + + [Test] + public async Task GetAuditLogEntries_WhenAuditEntityHasNoDisplayName_DisplayNameIsSetIsEntityShortName() + { + //Arrange + var auditEntry = new AuditEntry + { + AuditLogId = 1, + DisplayName = "Test DisplayName", + EntityName = "AuditLog.UnitTests.TestEntityTwo", + IsPrimary = true, + Id = 1, + PrimaryKey = "{{ \"id\": 1 }}", + AuditLog = new AuditDetail + { + Id = 10, + Comment = "Testing", + DateTime = new DateTimeOffset(2023, 06, 15, 23, 56, 37, TimeSpan.Zero), + UserDisplayName = "Testy McTester", + UserId = 666, + Fields = "", + Type = "Add" + } + + }; + + AuditLogRepository.AuditEntries.Add(auditEntry); + + var logEntry = "ewogICJlbnRpdHlOYW1lIjoiVGVzdEVudGl0eSIsCiAgInByaW1hcnlLZXkiOiJ7aWQ6MTAxfSIKfQ=="; + + var paging = new Paging(); + + //Act + var result = await AuditLog.GetAuditLogEntries(paging, logEntry, false, default); + + //Assert + var actualResult = result.Data.FirstOrDefault(); + Assert.Multiple(() => + { + Assert.That(actualResult, Is.Not.Null); + Assert.That(actualResult!.EntityDisplayName, Is.EqualTo("TestEntityTwo")); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/AuditLog.UnitTests/Helpers/AuditLogTestBase.cs b/e-suite.Modules.AuditLog/AuditLog.UnitTests/Helpers/AuditLogTestBase.cs new file mode 100644 index 0000000..96f5dc7 --- /dev/null +++ b/e-suite.Modules.AuditLog/AuditLog.UnitTests/Helpers/AuditLogTestBase.cs @@ -0,0 +1,21 @@ +using AuditLog.UnitTests.Repository; +using e_suite.API.Common; +using e_suite.UnitTestCore; + +namespace AuditLog.UnitTests.Helpers; + +public class AuditLogTestBase : TestBase +{ + protected IAuditLog AuditLog = null!; + + protected FakeAuditLogRepository AuditLogRepository { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + AuditLogRepository = new FakeAuditLogRepository(); + + AuditLog = new e_suite.Modules.AuditLog.AuditLog(AuditLogRepository); + } +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/AuditLog.UnitTests/Repository/FakeAuditLogRepository.cs b/e-suite.Modules.AuditLog/AuditLog.UnitTests/Repository/FakeAuditLogRepository.cs new file mode 100644 index 0000000..5d629bc --- /dev/null +++ b/e-suite.Modules.AuditLog/AuditLog.UnitTests/Repository/FakeAuditLogRepository.cs @@ -0,0 +1,19 @@ +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit.Tables.Audit; +using MockQueryable; + +namespace AuditLog.UnitTests.Repository; + +public class FakeAuditLogRepository : IAuditLogRepository +{ + public List AuditEntries { get; set; } = []; + + public AuditParams? AuditParams { get; set; } + + public IQueryable GetAuditEntries(AuditParams? auditParams, bool primaryOnly) + { + AuditParams = auditParams; + return AuditEntries.BuildMock(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/AuditLog.UnitTests/TestEntity.cs b/e-suite.Modules.AuditLog/AuditLog.UnitTests/TestEntity.cs new file mode 100644 index 0000000..5da7033 --- /dev/null +++ b/e-suite.Modules.AuditLog/AuditLog.UnitTests/TestEntity.cs @@ -0,0 +1,14 @@ +using System.ComponentModel; + +namespace AuditLog.UnitTests; + +//note: used by unit test GetAuditLogEntries_WhenAuditEntityHasDisplayName_DisplayNameIsSetIsEntityDisplayname + +[DisplayName("Test display name")] +public class TestEntity +{ +} + +public class TestEntityTwo +{ +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/README.md b/e-suite.Modules.AuditLog/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.AuditLog/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/azure-pipelines.yml b/e-suite.Modules.AuditLog/azure-pipelines.yml new file mode 100644 index 0000000..70a9ea2 --- /dev/null +++ b/e-suite.Modules.AuditLog/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '70' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.sln b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.sln new file mode 100644 index 0000000..3c11329 --- /dev/null +++ b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.AuditLog", "e-suite.Modules.AuditLog\e-suite.Modules.AuditLog.csproj", "{7D19FB1C-81AD-4717-BB7D-C74DAC7EA0F8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{2C77CC3A-6B9C-4E0F-8174-26F458114610}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{9AC1C078-9AC5-4581-9E70-6748E9655A3C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuditLog.UnitTests", "AuditLog.UnitTests\AuditLog.UnitTests.csproj", "{CA227AE8-5F0D-47F6-9592-B02085FD2A80}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7D19FB1C-81AD-4717-BB7D-C74DAC7EA0F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D19FB1C-81AD-4717-BB7D-C74DAC7EA0F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D19FB1C-81AD-4717-BB7D-C74DAC7EA0F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D19FB1C-81AD-4717-BB7D-C74DAC7EA0F8}.Release|Any CPU.Build.0 = Release|Any CPU + {CA227AE8-5F0D-47F6-9592-B02085FD2A80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA227AE8-5F0D-47F6-9592-B02085FD2A80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA227AE8-5F0D-47F6-9592-B02085FD2A80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA227AE8-5F0D-47F6-9592-B02085FD2A80}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9AC1C078-9AC5-4581-9E70-6748E9655A3C} = {2C77CC3A-6B9C-4E0F-8174-26F458114610} + {CA227AE8-5F0D-47F6-9592-B02085FD2A80} = {9AC1C078-9AC5-4581-9E70-6748E9655A3C} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0802DC7D-C3DA-4609-8176-437484C306BC} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/AuditLog.cs b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/AuditLog.cs new file mode 100644 index 0000000..bb26059 --- /dev/null +++ b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/AuditLog.cs @@ -0,0 +1,134 @@ +using System.ComponentModel; +using System.Linq.Expressions; +using System.Text.Json; +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit.Tables.Audit; +using e_suite.Utilities.Pagination; + +namespace e_suite.Modules.AuditLog; + +public class AuditLog : IAuditLog +{ + private readonly IAuditLogRepository _auditLogRepository; + + public AuditLog(IAuditLogRepository auditLogRepository) + { + _auditLogRepository = auditLogRepository; + } + + public async Task> GetAuditLogEntries(Paging paging, string? logEntry, bool primaryOnly, CancellationToken cancellationToken) + { + AuditParams? auditParams = null; + if (logEntry != null) + { + var buffer = Convert.FromBase64String(logEntry); + auditParams = JsonSerializer.Deserialize(buffer); + } + + var auditEntries = _auditLogRepository.GetAuditEntries(auditParams, primaryOnly); + + var paginatedData = + await PaginatedData.Paginate(auditEntries, paging, KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(x => new AuditLogEntry + { + Id = x.Id, + UserId = x.AuditLog.UserId, + UserDisplayName = x.AuditLog.UserDisplayName, + Type = x.AuditLog.Type, + DateTime = x.AuditLog.DateTime, + Fields = x.AuditLog.Fields, + Comment = x.AuditLog.Comment, + EntityName = x.EntityName, + EntityDisplayName = GetDisplayNameForClass( x.EntityName ), + PrimaryKey = x.PrimaryKey, + DisplayName = x.DisplayName ?? string.Empty + }) + }; + + return paginatedResult; + } + + private string GetDisplayNameForClass(string entityName) + { + var type = GetTypeFromFullName(entityName); + + if (type != null) + { + var displayName = GetDisplayName(type); + if (displayName != null) + return displayName; + + return type.Name; + } + + return entityName; + } + + private static string? GetDisplayName(Type type) + { + return (from attribute in type.CustomAttributes where attribute.AttributeType == typeof(DisplayNameAttribute) select attribute.ConstructorArguments[0].ToString().Trim('"')).FirstOrDefault(); + } + + private readonly Dictionary cacheDictionary = new(); + + private Type? GetTypeFromFullName(string className) + { + if (cacheDictionary.TryGetValue(className, out var name)) + return name; + + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (var type in assembly.GetTypes()) + { + if (type.FullName == null || + !type.FullName.Equals(className, StringComparison.OrdinalIgnoreCase)) + continue; + + cacheDictionary.Add(className, type); + return type; + } + } + + return null; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "userdisplayname" => x => x.AuditLog.UserDisplayName.Contains(value), + "type" => x => x.AuditLog.Type.Contains(value), + "comment" => x => x.AuditLog.Comment.Contains(value), + "displayname" => x => x.DisplayName!.Contains(value), + _ => x => true + }; + + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "userid" => x => x.AuditLog.UserId, + "userdisplayname" => x => x.AuditLog.UserDisplayName, + "type" => x => x.AuditLog.Type, + "datetime" => x => x.AuditLog.DateTime, + "fields" => x => x.AuditLog.Fields, + "comment" => x => x.AuditLog.Comment, + "entityname" => x => x.EntityName, + "primarykey" => x => x.PrimaryKey, + "displayname" => x => x.DisplayName!, + _ => x => x.AuditLog.DateTime + }; + } +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/IocRegistration.cs b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/IocRegistration.cs new file mode 100644 index 0000000..f9c711a --- /dev/null +++ b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.AuditLog.repository; + +namespace e_suite.Modules.AuditLog; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.csproj b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.csproj new file mode 100644 index 0000000..dfc5b0d --- /dev/null +++ b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + e_suite.Modules.AuditLog + enable + enable + + + + + + + + + + + diff --git a/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/repository/AuditLogRepository.cs b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/repository/AuditLogRepository.cs new file mode 100644 index 0000000..a662f87 --- /dev/null +++ b/e-suite.Modules.AuditLog/e-suite.Modules.AuditLog/repository/AuditLogRepository.cs @@ -0,0 +1,38 @@ +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit.Tables.Audit; +using e_suite.Database.Core; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.AuditLog.repository; + +public class AuditLogRepository : RepositoryBase, IAuditLogRepository +{ + public AuditLogRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetAuditEntries(AuditParams? auditParams, bool primaryOnly) + { + IQueryable queryable = DatabaseDbContext.AuditEntries + .Include(ae_view => ae_view.AuditLog); + + if (primaryOnly) + { + queryable = queryable + .Where(ae_view => ae_view.IsPrimary); + } + + if (auditParams != null) + { + return queryable.Join(DatabaseDbContext.AuditEntries + .Where(ae_lookup => ae_lookup.EntityName == auditParams.EntityName && + ae_lookup.PrimaryKey == auditParams.PrimaryKey), + ae_lookup => ae_lookup.AuditLogId, + ae_view => ae_view.AuditLogId, + (ae_lookup, ae_view) => ae_lookup); + } + + return queryable; + } +} \ No newline at end of file diff --git a/e-suite.Modules.AuditLog/nuget.config b/e-suite.Modules.AuditLog/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.AuditLog/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/README.md b/e-suite.Modules.ContactsManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.ContactsManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Castle.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Castle.Core.dll new file mode 100644 index 0000000..eb7fd3b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Castle.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests new file mode 100644 index 0000000..f2f1769 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Abstractions.dll new file mode 100644 index 0000000..5ca9acd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Cookies.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Cookies.dll new file mode 100644 index 0000000..b37e183 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Cookies.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Core.dll new file mode 100644 index 0000000..484ad0d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.dll new file mode 100644 index 0000000..d502117 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Authentication.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Cryptography.Internal.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Cryptography.Internal.dll new file mode 100644 index 0000000..59cea5b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Cryptography.Internal.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll new file mode 100644 index 0000000..73a7cc6 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll new file mode 100644 index 0000000..9346eec Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.DataProtection.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.DataProtection.dll new file mode 100644 index 0000000..e5f90fc Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.DataProtection.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Hosting.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Hosting.Abstractions.dll new file mode 100644 index 0000000..2fa7ecb Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Hosting.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll new file mode 100644 index 0000000..2692258 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Abstractions.dll new file mode 100644 index 0000000..c817782 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Extensions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Extensions.dll new file mode 100644 index 0000000..3dfb5e0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Extensions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Features.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Features.dll new file mode 100644 index 0000000..c5f6f86 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.Features.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.dll new file mode 100644 index 0000000..c2c59cf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Http.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Identity.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Identity.dll new file mode 100644 index 0000000..2bb7b84 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.Identity.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.WebUtilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.WebUtilities.dll new file mode 100644 index 0000000..dc1e804 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.AspNetCore.WebUtilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll new file mode 100644 index 0000000..608e35e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.EntityFrameworkCore.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.EntityFrameworkCore.dll new file mode 100644 index 0000000..3671f9e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.EntityFrameworkCore.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Caching.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Caching.Abstractions.dll new file mode 100644 index 0000000..be73869 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Caching.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Caching.Memory.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Caching.Memory.dll new file mode 100644 index 0000000..561804a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Caching.Memory.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..3a12ec4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Configuration.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..8baf931 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Configuration.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll new file mode 100644 index 0000000..11e5f2e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.DependencyInjection.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.DependencyInjection.dll new file mode 100644 index 0000000..2c64257 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.DependencyInjection.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..bca3315 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Hosting.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Hosting.Abstractions.dll new file mode 100644 index 0000000..8f4da6f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Hosting.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Identity.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Identity.Core.dll new file mode 100644 index 0000000..f8a5a37 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Identity.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Logging.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Logging.Abstractions.dll new file mode 100644 index 0000000..03edd8f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Logging.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Logging.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Logging.dll new file mode 100644 index 0000000..c53f5d2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Logging.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.ObjectPool.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.ObjectPool.dll new file mode 100644 index 0000000..5330caf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.ObjectPool.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Options.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Options.dll new file mode 100644 index 0000000..3987d66 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Options.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Primitives.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..081abea Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.Primitives.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.WebEncoders.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.WebEncoders.dll new file mode 100644 index 0000000..4e3a0bf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Extensions.WebEncoders.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Net.Http.Headers.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Net.Http.Headers.dll new file mode 100644 index 0000000..01dec16 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.Net.Http.Headers.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CommunicationUtilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CommunicationUtilities.dll new file mode 100644 index 0000000..e45af4e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CommunicationUtilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CoreUtilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CoreUtilities.dll new file mode 100644 index 0000000..c868e1f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CoreUtilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CrossPlatEngine.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CrossPlatEngine.dll new file mode 100644 index 0000000..8201a76 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.CrossPlatEngine.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.PlatformAbstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.PlatformAbstractions.dll new file mode 100644 index 0000000..36c3817 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.PlatformAbstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.Utilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.Utilities.dll new file mode 100644 index 0000000..75e8966 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.TestPlatform.Utilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.CodeCoverage.Shim.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.CodeCoverage.Shim.dll new file mode 100644 index 0000000..224bb02 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.CodeCoverage.Shim.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.TestPlatform.Common.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.TestPlatform.Common.dll new file mode 100644 index 0000000..357b697 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.TestPlatform.Common.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll new file mode 100644 index 0000000..4e17acc Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Moq.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Moq.dll new file mode 100644 index 0000000..3b1106a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Moq.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NUnit3.TestAdapter.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NUnit3.TestAdapter.dll new file mode 100644 index 0000000..daa5082 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NUnit3.TestAdapter.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NUnit3.TestAdapter.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NUnit3.TestAdapter.pdb new file mode 100644 index 0000000..a518c9b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NUnit3.TestAdapter.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Newtonsoft.Json.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Newtonsoft.Json.dll new file mode 100644 index 0000000..8ba89bf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/Newtonsoft.Json.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NuGet.Frameworks.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NuGet.Frameworks.dll new file mode 100644 index 0000000..0fabf0c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/NuGet.Frameworks.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Diagnostics.EventLog.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Diagnostics.EventLog.dll new file mode 100644 index 0000000..8a65e71 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Diagnostics.EventLog.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Linq.Dynamic.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Linq.Dynamic.Core.dll new file mode 100644 index 0000000..35271d1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Linq.Dynamic.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Cryptography.Pkcs.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..b20c158 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Cryptography.Pkcs.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Cryptography.Xml.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Cryptography.Xml.dll new file mode 100644 index 0000000..3abfc08 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Cryptography.Xml.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Permissions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Permissions.dll new file mode 100644 index 0000000..d1af38f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/System.Security.Permissions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..cb28e97 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..b9f081d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..74ebedb Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..98cbcb7 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..7333544 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..7bfd5b1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..6a248d6 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..a1861dd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..505dddd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..4645b6b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.deps.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.deps.json new file mode 100644 index 0000000..12f094a --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.deps.json @@ -0,0 +1,1436 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "e-Suite.Modules.ContactsManager.UnitTests/1.0.0": { + "dependencies": { + "Microsoft.NET.Test.Sdk": "17.6.0", + "NUnit": "3.13.3", + "NUnit3TestAdapter": "4.4.2", + "coverlet.collector": "6.0.0", + "e-Suite.Modules.ContactsManager": "1.0.0", + "e-suite.Database.Core": "2023.5.17.2-beta", + "e-suite.UnitTestCore": "2023.5.16.1-beta" + }, + "runtime": { + "e-Suite.Modules.ContactsManager.UnitTests.dll": {} + } + }, + "Castle.Core/5.1.1": { + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + }, + "runtime": { + "lib/net6.0/Castle.Core.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.1.1.0" + } + } + }, + "coverlet.collector/6.0.0": {}, + "e-suite.API.Common/2023.5.23.18-beta": { + "dependencies": { + "e-suite.Database.Core": "2023.5.17.2-beta", + "e-suite.Utilities.Pagination": "2023.5.16.1-beta" + }, + "runtime": { + "lib/net6.0/e-suite.API.Common.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Audit/2023.5.16.1-beta": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.5", + "Newtonsoft.Json": "13.0.2", + "System.Linq.Dynamic.Core": "1.2.25", + "eSuite.Core": "2023.3.31.1-beta" + }, + "runtime": { + "lib/net6.0/e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/2023.5.17.2-beta": { + "dependencies": { + "e-suite.Database.Audit": "2023.5.16.1-beta", + "e_suite.Nuget.PasswordHasher": "2022.12.1.1" + }, + "runtime": { + "lib/net6.0/e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.UnitTestCore/2023.5.16.1-beta": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Moq": "4.18.4", + "e-suite.Database.Core": "2023.5.17.2-beta", + "eSuite.Core": "2023.3.31.1-beta" + }, + "runtime": { + "lib/net6.0/e-suite.UnitTestCore.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.5" + }, + "runtime": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/2023.3.31.1-beta": { + "runtime": { + "lib/net6.0/eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "dependencies": { + "Microsoft.AspNetCore.Identity": "2.2.0" + }, + "runtime": { + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication.Core": "2.2.0", + "Microsoft.AspNetCore.DataProtection": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.WebEncoders": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0" + }, + "runtime": { + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0", + "Microsoft.AspNetCore.DataProtection.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Win32.Registry": "4.5.0", + "System.Security.Cryptography.Xml": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Hosting.Server.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Hosting.Abstractions": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.AspNetCore.WebUtilities": "2.2.0", + "Microsoft.Extensions.ObjectPool": "2.2.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Net.Http.Headers": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Buffers": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication.Cookies": "2.2.0", + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.Identity.Core": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "dependencies": { + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.CodeCoverage/17.6.0": { + "runtime": { + "lib/netcoreapp3.1/Microsoft.VisualStudio.CodeCoverage.Shim.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.600.1123.17103" + } + } + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.5", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.5", + "Microsoft.Extensions.Caching.Memory": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "7.0.5.0", + "fileVersion": "7.0.523.16503" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "7.0.5.0", + "fileVersion": "7.0.523.16503" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": {}, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18315" + } + } + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.ComponentModel.Annotations": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.Extensions.Logging/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18315" + } + } + }, + "Microsoft.Extensions.Options/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0", + "System.Buffers": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.NET.Test.Sdk/17.6.0": { + "dependencies": { + "Microsoft.CodeCoverage": "17.6.0", + "Microsoft.TestPlatform.TestHost": "17.6.0" + } + }, + "Microsoft.NETCore.Platforms/2.0.0": {}, + "Microsoft.TestPlatform.ObjectModel/17.6.0": { + "dependencies": { + "NuGet.Frameworks": "5.11.0", + "System.Reflection.Metadata": "1.6.0" + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + }, + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + }, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + } + }, + "resources": { + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.TestPlatform.TestHost/17.6.0": { + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.6.0", + "Newtonsoft.Json": "13.0.2" + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CommunicationUtilities.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + }, + "lib/netcoreapp3.1/Microsoft.TestPlatform.CrossPlatEngine.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + }, + "lib/netcoreapp3.1/Microsoft.TestPlatform.Utilities.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + }, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.Common.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + }, + "lib/netcoreapp3.1/testhost.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "15.0.0.0" + } + }, + "resources": { + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.Win32.Registry/4.5.0": { + "dependencies": { + "System.Security.AccessControl": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "Moq/4.18.4": { + "dependencies": { + "Castle.Core": "5.1.1" + }, + "runtime": { + "lib/net6.0/Moq.dll": { + "assemblyVersion": "4.18.0.0", + "fileVersion": "4.18.4.0" + } + } + }, + "NETStandard.Library/2.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + } + }, + "Newtonsoft.Json/13.0.2": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.2.27524" + } + } + }, + "NuGet.Frameworks/5.11.0": { + "runtime": { + "lib/netstandard2.0/NuGet.Frameworks.dll": { + "assemblyVersion": "5.11.0.10", + "fileVersion": "5.11.0.10" + } + } + }, + "NUnit/3.13.3": { + "dependencies": { + "NETStandard.Library": "2.0.0" + }, + "runtime": { + "lib/netstandard2.0/nunit.framework.dll": { + "assemblyVersion": "3.13.3.0", + "fileVersion": "3.13.3.0" + } + } + }, + "NUnit3TestAdapter/4.4.2": {}, + "System.Buffers/4.5.0": {}, + "System.ComponentModel.Annotations/4.5.0": {}, + "System.Diagnostics.EventLog/6.0.0": { + "runtime": { + "lib/net6.0/System.Diagnostics.EventLog.dll": { + "assemblyVersion": "6.0.0.0", + "fileVersion": "6.0.21.52210" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "6.0.0.0", + "fileVersion": "0.0.0.0" + }, + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "6.0.0.0", + "fileVersion": "6.0.21.52210" + } + } + }, + "System.Linq.Dynamic.Core/1.2.25": { + "runtime": { + "lib/net6.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.2.25.0", + "fileVersion": "1.2.25.0" + } + } + }, + "System.Reflection.Metadata/1.6.0": {}, + "System.Runtime.CompilerServices.Unsafe/6.0.0": {}, + "System.Security.AccessControl/4.5.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "System.Security.Cryptography.Cng/4.5.0": {}, + "System.Security.Cryptography.Pkcs/4.5.0": { + "dependencies": { + "System.Security.Cryptography.Cng": "4.5.0" + }, + "runtime": { + "lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.6.26515.6" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Security.Cryptography.Xml/4.5.0": { + "dependencies": { + "System.Security.Cryptography.Pkcs": "4.5.0", + "System.Security.Permissions": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/System.Security.Cryptography.Xml.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Security.Permissions/4.5.0": { + "dependencies": { + "System.Security.AccessControl": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/System.Security.Permissions.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Security.Principal.Windows/4.5.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + } + }, + "System.Text.Encodings.Web/4.5.0": {}, + "e-Suite.Modules.ContactsManager/1.0.0": { + "dependencies": { + "e-suite.API.Common": "2023.5.23.18-beta", + "e-suite.Database.Core": "2023.5.17.2-beta" + }, + "runtime": { + "e-Suite.Modules.ContactsManager.dll": {} + } + } + } + }, + "libraries": { + "e-Suite.Modules.ContactsManager.UnitTests/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Castle.Core/5.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "path": "castle.core/5.1.1", + "hashPath": "castle.core.5.1.1.nupkg.sha512" + }, + "coverlet.collector/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ==", + "path": "coverlet.collector/6.0.0", + "hashPath": "coverlet.collector.6.0.0.nupkg.sha512" + }, + "e-suite.API.Common/2023.5.23.18-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-8h39GbWtL3ljouEHEcXsfngRACkZTA5ejzFy5r2fc2eejK4JHwkZakSdrqXZJNX8pt/BaN5XWgLUPkCwpT3iNw==", + "path": "e-suite.api.common/2023.5.23.18-beta", + "hashPath": "e-suite.api.common.2023.5.23.18-beta.nupkg.sha512" + }, + "e-suite.Database.Audit/2023.5.16.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+gSdDGHoiLA1w45KXb+REsgumVjsluPrNv5tJdj5i39U0uSvnkJssK9IMdxSh+t+b3wL33NhHiJ1jRFNUoGOAQ==", + "path": "e-suite.database.audit/2023.5.16.1-beta", + "hashPath": "e-suite.database.audit.2023.5.16.1-beta.nupkg.sha512" + }, + "e-suite.Database.Core/2023.5.17.2-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5jJ2ZPF2ddeS6sakLTESeLSRhFV3Gv8R/yBjzc2H6opkzuaXIH1YuewkM5XAEzwKyRhyBdAeyjIM/l8QalrPFQ==", + "path": "e-suite.database.core/2023.5.17.2-beta", + "hashPath": "e-suite.database.core.2023.5.17.2-beta.nupkg.sha512" + }, + "e-suite.UnitTestCore/2023.5.16.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WOn0c2ctnbYuHnb/MpXcRwmcDYI+m0Iae9Zm3ohK7PrIz84L/8ozd51/pC8h7R1SZje2aBlsVVJYn3CLmKJi9w==", + "path": "e-suite.unittestcore/2023.5.16.1-beta", + "hashPath": "e-suite.unittestcore.2023.5.16.1-beta.nupkg.sha512" + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0k9sjGp9YZpRUQaiyBkQpmslJTMOJ7ZR/f8Latc02Amcw953pB//CN+/XGGOO09FuxA3cWIsDQ9WsSEVU9iwxg==", + "path": "e-suite.utilities.pagination/2023.5.16.1-beta", + "hashPath": "e-suite.utilities.pagination.2023.5.16.1-beta.nupkg.sha512" + }, + "eSuite.Core/2023.3.31.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U1cmpMvZwNHk72F6C1r6ZEVuXVQDj10PxRGGG3g5iDWoGDEyCTImtKnZ4V2N/SesmZ87PCYrPsZdfVvjbHlJGA==", + "path": "esuite.core/2023.3.31.1-beta", + "hashPath": "esuite.core.2023.3.31.1-beta.nupkg.sha512" + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-oKt0q1UISYgWj9v72yIEhvYkcdHiw8SNIQUkE+DZJ1FuVkCqPknzMiFIZY3FKGZOQf0XY1pgccazZPyl+06VWQ==", + "path": "e_suite.nuget.passwordhasher/2022.12.1.1", + "hashPath": "e_suite.nuget.passwordhasher.2022.12.1.1.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-b0R9X7L6zMqNsssKDvhYHuNi5x0s4DyHTeXybIAyGaitKiW1Q5aAGKdV2codHPiePv9yHfC9hAMyScXQ/xXhPw==", + "path": "microsoft.aspnetcore.authentication/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VloMLDJMf3n/9ic5lCBOa42IBYJgyB1JhzLsL68Zqg+2bEPWfGBj/xCJy/LrKTArN0coOcZp3wyVTZlx0y9pHQ==", + "path": "microsoft.aspnetcore.authentication.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Iar9VFlBHkZGdSG9ZUTmn6Q8Qg+6CtW5G/TyJI2F8B432TOH+nZlkU7O0W0byow6xsxqOYeTviSHz4cCJ3amfQ==", + "path": "microsoft.aspnetcore.authentication.cookies/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XlVJzJ5wPOYW+Y0J6Q/LVTEyfS4ssLXmt60T0SPP+D8abVhBTl+cgw2gDHlyKYIkcJg7btMVh383NDkMVqD/fg==", + "path": "microsoft.aspnetcore.authentication.core/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-GXmMD8/vuTLPLvKzKEPz/4vapC5e0cwx1tUVd83ePRyWF9CCrn/pg4/1I+tGkQqFLPvi3nlI2QtPtC6MQN8Nww==", + "path": "microsoft.aspnetcore.cryptography.internal/2.2.0", + "hashPath": "microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NCY0PH3nrFYbhqiq72rwWsUXlV4OAE0MOukvGvIBOTnEPMC1yVL42k1DXLnaIu+c0yfMAxIIG9Iuaykp9BQQQw==", + "path": "microsoft.aspnetcore.cryptography.keyderivation/2.2.0", + "hashPath": "microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-G6dvu5Nd2vjpYbzazZ//qBFbSEf2wmBUbyAR7E4AwO3gWjhoJD5YxpThcGJb7oE3VUcW65SVMXT+cPCiiBg8Sg==", + "path": "microsoft.aspnetcore.dataprotection/2.2.0", + "hashPath": "microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-seANFXmp8mb5Y12m1ShiElJ3ZdOT3mBN3wA1GPhHJIvZ/BxOCPyqEOR+810OWsxEZwA5r5fDRNpG/CqiJmQnJg==", + "path": "microsoft.aspnetcore.dataprotection.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ubycklv+ZY7Kutdwuy1W4upWcZ6VFR8WUXU7l7B2+mvbDBBPAcfpi+E+Y5GFe+Q157YfA3C49D2GCjAZc7Mobw==", + "path": "microsoft.aspnetcore.hosting.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1PMijw8RMtuQF60SsD/JlKtVfvh4NORAhF4wjysdABhlhTrYmtgssqyncR0Stq5vqtjplZcj6kbT4LRTglt9IQ==", + "path": "microsoft.aspnetcore.hosting.server.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-YogBSMotWPAS/X5967pZ+yyWPQkThxhmzAwyCHCSSldzYBkW5W5d6oPfBaPqQOnSHYTpSOSOkpZoAce0vwb6+A==", + "path": "microsoft.aspnetcore.http/2.2.0", + "hashPath": "microsoft.aspnetcore.http.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==", + "path": "microsoft.aspnetcore.http.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2DgZ9rWrJtuR7RYiew01nGRzuQBDaGHGmK56Rk54vsLLsCdzuFUPqbDTJCS1qJQWTbmbIQ9wGIOjpxA1t0l7/w==", + "path": "microsoft.aspnetcore.http.extensions/2.2.0", + "hashPath": "microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==", + "path": "microsoft.aspnetcore.http.features/2.2.0", + "hashPath": "microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-F16BKeS96wKhyIyhaFR7m8kRIwIvPUW9Dx7IlGWmu2IIwnUDCdo+2z7IrWKA8r77pZQ1UE9kYcBPg5456YdAIA==", + "path": "microsoft.aspnetcore.identity/2.2.0", + "hashPath": "microsoft.aspnetcore.identity.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9ErxAAKaDzxXASB/b5uLEkLgUWv1QbeVxyJYEHQwMaxXOeFFVkQxiq8RyfVcifLU7NR0QY0p3acqx4ZpYfhHDg==", + "path": "microsoft.aspnetcore.webutilities/2.2.0", + "hashPath": "microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512" + }, + "Microsoft.CodeCoverage/17.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5v2GwzpR7JEuQUzupjx3zLwn2FutADW/weLzLt726DR3WXxsM+ICPoJG6pxuKFsumtZp890UrVuudTUhsE8Qyg==", + "path": "microsoft.codecoverage/17.6.0", + "hashPath": "microsoft.codecoverage.17.6.0.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RXbRLHHWP2Z3pq8qcL5nQ6LPeoOyp8hasM5bd0Te8PiQi3RjWQR4tcbdY5XMqQ+oTO9wA8/RLhZRn/hnxlTDnQ==", + "path": "microsoft.entityframeworkcore/7.0.5", + "hashPath": "microsoft.entityframeworkcore.7.0.5.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-iwQso+hFRsEWjhH2WsEQj1D2QE5BlEXiXEt6A3SlYTPRPdZsyTNDeDDEdtxL+H/UJPQgQYY+9SMMRcEiXBmCAA==", + "path": "microsoft.entityframeworkcore.abstractions/7.0.5", + "hashPath": "microsoft.entityframeworkcore.abstractions.7.0.5.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yMLM/aK1MikVqpjxd7PJ1Pjgztd3VAd26ZHxyjxG3RPeM9cHjvS5tCg9kAAayR6eHmBg0ffZsHdT28WfA5tTlA==", + "path": "microsoft.entityframeworkcore.analyzers/7.0.5", + "hashPath": "microsoft.entityframeworkcore.analyzers.7.0.5.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IeimUd0TNbhB4ded3AbgBLQv2SnsiVugDyGV1MvspQFVlA07nDC7Zul7kcwH5jWN3JiTcp/ySE83AIJo8yfKjg==", + "path": "microsoft.extensions.caching.abstractions/7.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-xpidBs2KCE2gw1JrD0quHE72kvCaI3xFql5/Peb2GRtUuZX+dYPoK/NTdVMiM67Svym0M0Df9A3xyU0FbMQhHw==", + "path": "microsoft.extensions.caching.memory/7.0.0", + "hashPath": "microsoft.extensions.caching.memory.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tldQUBWt/xeH2K7/hMPPo5g8zuLc3Ro9I5d4o/XrxvxOCA2EZBtW7bCHHTc49fcBtvB8tLAb/Qsmfrq+2SJ4vA==", + "path": "microsoft.extensions.configuration/7.0.0", + "hashPath": "microsoft.extensions.configuration.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==", + "path": "microsoft.extensions.configuration.abstractions/7.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-EcnaSsPTqx2MGnHrmWOD0ugbuuqVT8iICqSqPzi45V5/MA1LjUNb0kwgcxBGqizV1R+WeBK7/Gw25Jzkyk9bIw==", + "path": "microsoft.extensions.fileproviders.abstractions/2.2.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+k4AEn68HOJat5gj1TWa6X28WlirNQO9sPIIeQbia+91n03esEtMSSoekSTpMjUzjqtJWQN3McVx0GvSPFHF/Q==", + "path": "microsoft.extensions.hosting.abstractions/2.2.0", + "hashPath": "microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/C+Valwg8IeUwDIunusittHivA9iyf82Jr1yeUFWO2zH2mDMMeYgjRyDLZqfL/7Vq94PEQsgv1XAaDfAX8msMw==", + "path": "microsoft.extensions.identity.core/2.2.0", + "hashPath": "microsoft.extensions.identity.core.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "path": "microsoft.extensions.logging/7.0.0", + "hashPath": "microsoft.extensions.logging.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-gA8H7uQOnM5gb+L0uTNjViHYr+hRDqCdfugheGo/MxQnuHzmhhzCBTIPm19qL1z1Xe0NEMabfcOBGv9QghlZ8g==", + "path": "microsoft.extensions.objectpool/2.2.0", + "hashPath": "microsoft.extensions.objectpool.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "path": "microsoft.extensions.options/7.0.0", + "hashPath": "microsoft.extensions.options.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==", + "path": "microsoft.extensions.primitives/7.0.0", + "hashPath": "microsoft.extensions.primitives.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-V8XcqYcpcdBAxUhLeyYcuKmxu4CtNQA9IphTnARpQGhkop4A93v2XgM3AtaVVJo3H2cDWxWM6aeO8HxkifREqw==", + "path": "microsoft.extensions.webencoders/2.2.0", + "hashPath": "microsoft.extensions.webencoders.2.2.0.nupkg.sha512" + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-iZNkjYqlo8sIOI0bQfpsSoMTmB/kyvmV2h225ihyZT33aTp48ZpF6qYnXxzSXmHt8DpBAwBTX+1s1UFLbYfZKg==", + "path": "microsoft.net.http.headers/2.2.0", + "hashPath": "microsoft.net.http.headers.2.2.0.nupkg.sha512" + }, + "Microsoft.NET.Test.Sdk/17.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tHyg4C6c89QvLv6Utz3xKlba4EeoyJyIz59Q1NrjRENV7gfGnSE6I+sYPIbVOzQttoo2zpHDgOK/p6Hw2OlD7A==", + "path": "microsoft.net.test.sdk/17.6.0", + "hashPath": "microsoft.net.test.sdk.17.6.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==", + "path": "microsoft.netcore.platforms/2.0.0", + "hashPath": "microsoft.netcore.platforms.2.0.0.nupkg.sha512" + }, + "Microsoft.TestPlatform.ObjectModel/17.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AA/rrf5zwC5/OBLEOajkhjbVTM3SvxRXy8kcQ8e4mJKojbyZvqqhpfNg362N9vXU94DLg9NUTFOAnoYVT0pTJw==", + "path": "microsoft.testplatform.objectmodel/17.6.0", + "hashPath": "microsoft.testplatform.objectmodel.17.6.0.nupkg.sha512" + }, + "Microsoft.TestPlatform.TestHost/17.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7YdgUcIeCPVKLC7n7LNKDiEHWc7z3brkkYPdUbDnFsvf6WvY9UfzS0VSUJ8P2NgN0CDSD223GCJFSjSBLZRqOQ==", + "path": "microsoft.testplatform.testhost/17.6.0", + "hashPath": "microsoft.testplatform.testhost.17.6.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+FWlwd//+Tt56316p00hVePBCouXyEzT86Jb3+AuRotTND0IYn0OO3obs1gnQEs/txEnt+rF2JBGLItTG+Be6A==", + "path": "microsoft.win32.registry/4.5.0", + "hashPath": "microsoft.win32.registry.4.5.0.nupkg.sha512" + }, + "Moq/4.18.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IOo+W51+7Afnb0noltJrKxPBSfsgMzTKCw+Re5AMx8l/vBbAbMDOynLik4+lBYIWDJSO0uV7Zdqt7cNb6RZZ+A==", + "path": "moq/4.18.4", + "hashPath": "moq.4.18.4.nupkg.sha512" + }, + "NETStandard.Library/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7jnbRU+L08FXKMxqUflxEXtVymWvNOrS8yHgu9s6EM8Anr6T/wIX4nZ08j/u3Asz+tCufp3YVwFSEvFTPYmBPA==", + "path": "netstandard.library/2.0.0", + "hashPath": "netstandard.library.2.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==", + "path": "newtonsoft.json/13.0.2", + "hashPath": "newtonsoft.json.13.0.2.nupkg.sha512" + }, + "NuGet.Frameworks/5.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==", + "path": "nuget.frameworks/5.11.0", + "hashPath": "nuget.frameworks.5.11.0.nupkg.sha512" + }, + "NUnit/3.13.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KNPDpls6EfHwC3+nnA67fh5wpxeLb3VLFAfLxrug6JMYDLHH6InaQIWR7Sc3y75d/9IKzMksH/gi08W7XWbmnQ==", + "path": "nunit/3.13.3", + "hashPath": "nunit.3.13.3.nupkg.sha512" + }, + "NUnit3TestAdapter/4.4.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-vA/iHYcR+LYw+pRWQugckC/zW2fXHaqMr2uA82NOBt8v4YK4wMJrQ7QC8XLc7PjetEZ96cPbBTWsDDtmQiRZTA==", + "path": "nunit3testadapter/4.4.2", + "hashPath": "nunit3testadapter.4.4.2.nupkg.sha512" + }, + "System.Buffers/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A==", + "path": "system.buffers/4.5.0", + "hashPath": "system.buffers.4.5.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==", + "path": "system.componentmodel.annotations/4.5.0", + "hashPath": "system.componentmodel.annotations.4.5.0.nupkg.sha512" + }, + "System.Diagnostics.EventLog/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==", + "path": "system.diagnostics.eventlog/6.0.0", + "hashPath": "system.diagnostics.eventlog.6.0.0.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.2.25": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qpkqDHLNxGR1qBNrdnnPfJFfsKSWy3nUELC/BWxP8vwSaf8vVwecZzXOV4B52yOGit94g0pLWJEe30a4L1tE7g==", + "path": "system.linq.dynamic.core/1.2.25", + "hashPath": "system.linq.dynamic.core.1.2.25.nupkg.sha512" + }, + "System.Reflection.Metadata/1.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==", + "path": "system.reflection.metadata/1.6.0", + "hashPath": "system.reflection.metadata.1.6.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==", + "path": "system.security.accesscontrol/4.5.0", + "hashPath": "system.security.accesscontrol.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Cng/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==", + "path": "system.security.cryptography.cng/4.5.0", + "hashPath": "system.security.cryptography.cng.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-TGQX51gxpY3K3I6LJlE2LAftVlIMqJf0cBGhz68Y89jjk3LJCB6SrwiD+YN1fkqemBvWGs+GjyMJukl6d6goyQ==", + "path": "system.security.cryptography.pkcs/4.5.0", + "hashPath": "system.security.cryptography.pkcs.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Xml/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-i2Jn6rGXR63J0zIklImGRkDIJL4b1NfPSEbIVHBlqoIb12lfXIigCbDRpDmIEzwSo/v1U5y/rYJdzZYSyCWxvg==", + "path": "system.security.cryptography.xml/4.5.0", + "hashPath": "system.security.cryptography.xml.4.5.0.nupkg.sha512" + }, + "System.Security.Permissions/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==", + "path": "system.security.permissions/4.5.0", + "hashPath": "system.security.permissions.4.5.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "path": "system.security.principal.windows/4.5.0", + "hashPath": "system.security.principal.windows.4.5.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==", + "path": "system.text.encodings.web/4.5.0", + "hashPath": "system.text.encodings.web.4.5.0.nupkg.sha512" + }, + "e-Suite.Modules.ContactsManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..423f8c4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.pdb new file mode 100644 index 0000000..a25eff6 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json new file mode 100644 index 0000000..03663c6 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.NullabilityInfoContext.IsSupported": true + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..4e15af0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb new file mode 100644 index 0000000..29203df Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.API.Common.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.API.Common.dll new file mode 100644 index 0000000..d3b567b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.API.Common.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Database.Audit.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Database.Audit.dll new file mode 100644 index 0000000..b3a264f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Database.Audit.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Database.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Database.Core.dll new file mode 100644 index 0000000..6688004 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Database.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Nuget.PasswordHasher.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Nuget.PasswordHasher.dll new file mode 100644 index 0000000..07bc591 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Nuget.PasswordHasher.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.UnitTestCore.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.UnitTestCore.dll new file mode 100644 index 0000000..b16b2a1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.UnitTestCore.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Utilities.Pagination.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Utilities.Pagination.dll new file mode 100644 index 0000000..b23958b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/e-suite.Utilities.Pagination.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/eSuite.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/eSuite.Core.dll new file mode 100644 index 0000000..9f4f321 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/eSuite.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..1668698 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..6bd079a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..6430c84 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..e683698 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..1442ee8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..c7759cf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..c207945 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..0bc035b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..8d900d5 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..6f0b7cd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..266057d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..0d3887a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..80d55d5 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..f7a9f3d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..6abdb0f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..3a39a78 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..ea6315e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..470173a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..0d53bff Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..b09e823 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..0114575 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..a0d681f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..6ad80ed Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..44520a2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..9aceed9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.api.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.api.dll new file mode 100644 index 0000000..0c03ad4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.api.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.core.dll new file mode 100644 index 0000000..cbda4d9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.dll new file mode 100644 index 0000000..6ab546f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.engine.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.framework.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.framework.dll new file mode 100644 index 0000000..16e3f3b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/nunit.framework.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..7dc061e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..ddce776 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..5d9cc06 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..9129485 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..93dfb6d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..6f009dc Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..a52d361 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..08d86f9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..9e7e899 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..4841034 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..d4f74e0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..f6b8ea3 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..c926fc1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..9aa81a0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..193cfe8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll new file mode 100644 index 0000000..bc23526 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll new file mode 100644 index 0000000..03b44f1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..08967c5 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testcentric.engine.metadata.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testcentric.engine.metadata.dll new file mode 100644 index 0000000..b982b6b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testcentric.engine.metadata.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testhost.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testhost.dll new file mode 100644 index 0000000..b15bd81 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testhost.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testhost.exe b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testhost.exe new file mode 100644 index 0000000..de9292b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/testhost.exe differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..0103c73 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..1af1a2b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..8208c4a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..1e34b72 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..764f76d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..cfbbe73 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..d8b7fb2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..1911bc8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..7de1876 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..c7908a2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..edb16db Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..432e72c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..82406ca Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..8545af8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..b2092e0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net6.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Castle.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Castle.Core.dll new file mode 100644 index 0000000..eb7fd3b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Castle.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests new file mode 100644 index 0000000..f2f1769 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.Abstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.Abstractions.dll new file mode 100644 index 0000000..bbe5da9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.Abstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.dll new file mode 100644 index 0000000..c8a8af4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CommunicationUtilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CommunicationUtilities.dll new file mode 100644 index 0000000..514e543 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CommunicationUtilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CoreUtilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CoreUtilities.dll new file mode 100644 index 0000000..67c6e6f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CoreUtilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CrossPlatEngine.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CrossPlatEngine.dll new file mode 100644 index 0000000..09efce0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.CrossPlatEngine.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.PlatformAbstractions.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.PlatformAbstractions.dll new file mode 100644 index 0000000..a18a266 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.PlatformAbstractions.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.Utilities.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.Utilities.dll new file mode 100644 index 0000000..22a03b8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.TestPlatform.Utilities.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.CodeCoverage.Shim.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.CodeCoverage.Shim.dll new file mode 100644 index 0000000..117ba73 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.CodeCoverage.Shim.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.TestPlatform.Common.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.TestPlatform.Common.dll new file mode 100644 index 0000000..8213a95 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.TestPlatform.Common.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll new file mode 100644 index 0000000..b002d6b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Moq.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Moq.dll new file mode 100644 index 0000000..3c9679c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Moq.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NUnit3.TestAdapter.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NUnit3.TestAdapter.dll new file mode 100644 index 0000000..65c8c3d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NUnit3.TestAdapter.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NUnit3.TestAdapter.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NUnit3.TestAdapter.pdb new file mode 100644 index 0000000..5a3a1b8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NUnit3.TestAdapter.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Newtonsoft.Json.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Newtonsoft.Json.dll new file mode 100644 index 0000000..8ba89bf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/Newtonsoft.Json.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NuGet.Frameworks.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NuGet.Frameworks.dll new file mode 100644 index 0000000..d78c478 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/NuGet.Frameworks.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/System.Linq.Dynamic.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/System.Linq.Dynamic.Core.dll new file mode 100644 index 0000000..3831072 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/System.Linq.Dynamic.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..1768037 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..7310fb0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..5af6e0e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..86c5af1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..d9a801b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..2bb1465 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..d457408 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..998dc29 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..3cd7988 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..e6266e6 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.deps.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.deps.json new file mode 100644 index 0000000..50fc82d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.deps.json @@ -0,0 +1,773 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "e-Suite.Modules.ContactsManager.UnitTests/1.0.0": { + "dependencies": { + "Microsoft.NET.Test.Sdk": "17.8.0", + "NUnit": "4.0.1", + "NUnit3TestAdapter": "4.5.0", + "coverlet.collector": "6.0.0", + "e-Suite.Modules.ContactsManager": "1.0.0", + "e-suite.Database.Core": "2024.1.2.5-alpha", + "e-suite.UnitTestCore": "2024.1.2.1-alpha" + }, + "runtime": { + "e-Suite.Modules.ContactsManager.UnitTests.dll": {} + } + }, + "Castle.Core/5.1.1": { + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + }, + "runtime": { + "lib/net6.0/Castle.Core.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.1.1.0" + } + } + }, + "coverlet.collector/6.0.0": {}, + "e-suite.API.Common/2024.1.2.1-alpha": { + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "e-suite.Database.Core": "2024.1.2.5-alpha", + "e-suite.Utilities.Pagination": "2023.7.25.3", + "eSuite.Core": "2024.1.2.1-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.API.Common.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Audit/2024.1.2.2-alpha": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.9", + "Newtonsoft.Json": "13.0.2", + "System.Linq.Dynamic.Core": "1.2.25", + "eSuite.Core": "2024.1.2.1-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/2024.1.2.5-alpha": { + "dependencies": { + "e-suite.Database.Audit": "2024.1.2.2-alpha", + "e_suite.Nuget.PasswordHasher": "2024.1.2.1-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.UnitTestCore/2024.1.2.1-alpha": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Moq": "4.20.70", + "e-suite.Database.Core": "2024.1.2.5-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.UnitTestCore.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/2023.7.25.3": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.9" + }, + "runtime": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/2024.1.2.1-alpha": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0" + }, + "runtime": { + "lib/net8.0/eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/2024.1.2.1-alpha": { + "runtime": { + "lib/net8.0/e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.CodeCoverage/17.8.0": { + "runtime": { + "lib/netcoreapp3.1/Microsoft.VisualStudio.CodeCoverage.Shim.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.623.45702" + } + } + }, + "Microsoft.EntityFrameworkCore/7.0.9": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.9", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.9", + "Microsoft.Extensions.Caching.Memory": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "7.0.9.0", + "fileVersion": "7.0.923.31909" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.9": { + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "7.0.9.0", + "fileVersion": "7.0.923.31909" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.9": {}, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": {}, + "Microsoft.Extensions.Logging/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": {}, + "Microsoft.Extensions.Options/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Primitives/8.0.0": {}, + "Microsoft.NET.Test.Sdk/17.8.0": { + "dependencies": { + "Microsoft.CodeCoverage": "17.8.0", + "Microsoft.TestPlatform.TestHost": "17.8.0" + } + }, + "Microsoft.TestPlatform.ObjectModel/17.8.0": { + "dependencies": { + "NuGet.Frameworks": "6.5.0", + "System.Reflection.Metadata": "1.6.0" + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + }, + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + }, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + } + }, + "resources": { + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.TestPlatform.TestHost/17.8.0": { + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.8.0", + "Newtonsoft.Json": "13.0.2" + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CommunicationUtilities.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + }, + "lib/netcoreapp3.1/Microsoft.TestPlatform.CrossPlatEngine.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + }, + "lib/netcoreapp3.1/Microsoft.TestPlatform.Utilities.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + }, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.Common.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + }, + "lib/netcoreapp3.1/testhost.dll": { + "assemblyVersion": "15.0.0.0", + "fileVersion": "17.800.23.55801" + } + }, + "resources": { + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Moq/4.20.70": { + "dependencies": { + "Castle.Core": "5.1.1" + }, + "runtime": { + "lib/net6.0/Moq.dll": { + "assemblyVersion": "4.20.70.0", + "fileVersion": "4.20.70.0" + } + } + }, + "Newtonsoft.Json/13.0.2": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.2.27524" + } + } + }, + "NuGet.Frameworks/6.5.0": { + "runtime": { + "lib/netstandard2.0/NuGet.Frameworks.dll": { + "assemblyVersion": "6.5.0.154", + "fileVersion": "6.5.0.154" + } + } + }, + "NUnit/4.0.1": { + "runtime": { + "lib/net6.0/nunit.framework.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.0.1.0" + }, + "lib/net6.0/nunit.framework.legacy.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.0.1.0" + } + } + }, + "NUnit3TestAdapter/4.5.0": {}, + "System.Diagnostics.EventLog/6.0.0": {}, + "System.Linq.Dynamic.Core/1.2.25": { + "runtime": { + "lib/net7.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.2.25.0", + "fileVersion": "1.2.25.0" + } + } + }, + "System.Reflection.Metadata/1.6.0": {}, + "e-Suite.Modules.ContactsManager/1.0.0": { + "dependencies": { + "e-suite.API.Common": "2024.1.2.1-alpha" + }, + "runtime": { + "e-Suite.Modules.ContactsManager.dll": {} + } + } + } + }, + "libraries": { + "e-Suite.Modules.ContactsManager.UnitTests/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Castle.Core/5.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "path": "castle.core/5.1.1", + "hashPath": "castle.core.5.1.1.nupkg.sha512" + }, + "coverlet.collector/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ==", + "path": "coverlet.collector/6.0.0", + "hashPath": "coverlet.collector.6.0.0.nupkg.sha512" + }, + "e-suite.API.Common/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-w4E9LNwvVEfAqUcK1J/DsandBQBsWCgNCZx394yh4Bz9ur8vS8ApqyVViWew9NbrJgyxeWLuTI35b00hB7l97g==", + "path": "e-suite.api.common/2024.1.2.1-alpha", + "hashPath": "e-suite.api.common.2024.1.2.1-alpha.nupkg.sha512" + }, + "e-suite.Database.Audit/2024.1.2.2-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kcgAX/Dwpmbe5s8xJkguax74DkAHPPDkHClZU13g17Uq9xA4fd3X7Yz93YqfBJ1y72pRNBnnBHABhgMEPAInKA==", + "path": "e-suite.database.audit/2024.1.2.2-alpha", + "hashPath": "e-suite.database.audit.2024.1.2.2-alpha.nupkg.sha512" + }, + "e-suite.Database.Core/2024.1.2.5-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ypg91t9N1kjeXKHw1nmZqctjYFQ4wZfZ/zGztkYfFXDclUmUgRvpPq0IRtMAnux5pJkmXz5mIAUP0UBNIu7VzA==", + "path": "e-suite.database.core/2024.1.2.5-alpha", + "hashPath": "e-suite.database.core.2024.1.2.5-alpha.nupkg.sha512" + }, + "e-suite.UnitTestCore/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-g4b4SjUWBWkFS3joLf4CL8fc0daN9iC+wwLcDojLBDhXioeWdpuZ1SfL9XN5BkPEbc714odL6LFgCGd+X3nrHA==", + "path": "e-suite.unittestcore/2024.1.2.1-alpha", + "hashPath": "e-suite.unittestcore.2024.1.2.1-alpha.nupkg.sha512" + }, + "e-suite.Utilities.Pagination/2023.7.25.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UM8RcXLFCva0hBtPGk4TN4boivylgpih5J3MlBcLMuIRZ9Bma/uE/pNCSk3IucremhhMOjaqEnGErXuxK3VyyA==", + "path": "e-suite.utilities.pagination/2023.7.25.3", + "hashPath": "e-suite.utilities.pagination.2023.7.25.3.nupkg.sha512" + }, + "eSuite.Core/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Ll/FLQldWCsM6KkRwkGbtvL+L7WAj/PxnPGIsA7QaD3Mum+VO+w6fBxgQJ2UcuQftLjL7kY1MszsC287EJEP9w==", + "path": "esuite.core/2024.1.2.1-alpha", + "hashPath": "esuite.core.2024.1.2.1-alpha.nupkg.sha512" + }, + "e_suite.Nuget.PasswordHasher/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4dpQkbSVpLa+6436T1Z2X+FltHLYJK2r2UZxD0TrrVWc2A6HPReM/RB5ZrIxapRxGzYdvUzOlMfR+Q62hn1CAQ==", + "path": "e_suite.nuget.passwordhasher/2024.1.2.1-alpha", + "hashPath": "e_suite.nuget.passwordhasher.2024.1.2.1-alpha.nupkg.sha512" + }, + "Microsoft.CodeCoverage/17.8.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KC8SXWbGIdoFVdlxKk9WHccm0llm9HypcHMLUUFabRiTS3SO2fQXNZfdiF3qkEdTJhbRrxhdRxjL4jbtwPq4Ew==", + "path": "microsoft.codecoverage/17.8.0", + "hashPath": "microsoft.codecoverage.17.8.0.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/7.0.9": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9YuCdQWuRAmYYHqwW1h5ukKMC1fmNvcVHdp3gb8zdHxwSQz7hkGpYOBEjm6dRXRmGRkpUyHL8rwUz4kd53Ev0A==", + "path": "microsoft.entityframeworkcore/7.0.9", + "hashPath": "microsoft.entityframeworkcore.7.0.9.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.9": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cfY6Fn7cnP/5pXndL8QYaey/B2nGn1fwze5aSaMJymmbqwqYzFiszHuWbsdVBCDYJc8ok7eB1m/nCc3/rltulQ==", + "path": "microsoft.entityframeworkcore.abstractions/7.0.9", + "hashPath": "microsoft.entityframeworkcore.abstractions.7.0.9.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.9": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VvqFD3DdML6LhPCAR/lG2xNX66juylC8v57yUAAYnUSdEUOMRi3lNoT4OrNdG0rere3UOQPhvVl5FH2QdyoF8Q==", + "path": "microsoft.entityframeworkcore.analyzers/7.0.9", + "hashPath": "microsoft.entityframeworkcore.analyzers.7.0.9.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IeimUd0TNbhB4ded3AbgBLQv2SnsiVugDyGV1MvspQFVlA07nDC7Zul7kcwH5jWN3JiTcp/ySE83AIJo8yfKjg==", + "path": "microsoft.extensions.caching.abstractions/7.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-xpidBs2KCE2gw1JrD0quHE72kvCaI3xFql5/Peb2GRtUuZX+dYPoK/NTdVMiM67Svym0M0Df9A3xyU0FbMQhHw==", + "path": "microsoft.extensions.caching.memory/7.0.0", + "hashPath": "microsoft.extensions.caching.memory.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Binder/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==", + "path": "microsoft.extensions.configuration.binder/8.0.0", + "hashPath": "microsoft.extensions.configuration.binder.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "path": "microsoft.extensions.logging/7.0.0", + "hashPath": "microsoft.extensions.logging.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "path": "microsoft.extensions.options/7.0.0", + "hashPath": "microsoft.extensions.options.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.NET.Test.Sdk/17.8.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-BmTYGbD/YuDHmApIENdoyN1jCk0Rj1fJB0+B/fVekyTdVidr91IlzhqzytiUgaEAzL1ZJcYCme0MeBMYvJVzvw==", + "path": "microsoft.net.test.sdk/17.8.0", + "hashPath": "microsoft.net.test.sdk.17.8.0.nupkg.sha512" + }, + "Microsoft.TestPlatform.ObjectModel/17.8.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AYy6vlpGMfz5kOFq99L93RGbqftW/8eQTqjT9iGXW6s9MRP3UdtY8idJ8rJcjeSja8A18IhIro5YnH3uv1nz4g==", + "path": "microsoft.testplatform.objectmodel/17.8.0", + "hashPath": "microsoft.testplatform.objectmodel.17.8.0.nupkg.sha512" + }, + "Microsoft.TestPlatform.TestHost/17.8.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9ivcl/7SGRmOT0YYrHQGohWiT5YCpkmy/UEzldfVisLm6QxbLaK3FAJqZXI34rnRLmqqDCeMQxKINwmKwAPiDw==", + "path": "microsoft.testplatform.testhost/17.8.0", + "hashPath": "microsoft.testplatform.testhost.17.8.0.nupkg.sha512" + }, + "Moq/4.20.70": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4rNnAwdpXJBuxqrOCzCyICXHSImOTRktCgCWXWykuF1qwoIsVvEnR7PjbMk/eLOxWvhmj5Kwt+kDV3RGUYcNwg==", + "path": "moq/4.20.70", + "hashPath": "moq.4.20.70.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==", + "path": "newtonsoft.json/13.0.2", + "hashPath": "newtonsoft.json.13.0.2.nupkg.sha512" + }, + "NuGet.Frameworks/6.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-QWINE2x3MbTODsWT1Gh71GaGb5icBz4chS8VYvTgsBnsi8esgN6wtHhydd7fvToWECYGq7T4cgBBDiKD/363fg==", + "path": "nuget.frameworks/6.5.0", + "hashPath": "nuget.frameworks.6.5.0.nupkg.sha512" + }, + "NUnit/4.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-jNTHZ01hJsDNPDSBycoHpavFZUBf9vRVQLCyuo78LRrrFj6Ol/CeqK+NIeTk5d8Eycjk59KseWb7X5Ge6z7CgQ==", + "path": "nunit/4.0.1", + "hashPath": "nunit.4.0.1.nupkg.sha512" + }, + "NUnit3TestAdapter/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s8JpqTe9bI2f49Pfr3dFRfoVSuFQyraTj68c3XXjIS/MRGvvkLnrg6RLqnTjdShX+AdFUCCU/4Xex58AdUfs6A==", + "path": "nunit3testadapter/4.5.0", + "hashPath": "nunit3testadapter.4.5.0.nupkg.sha512" + }, + "System.Diagnostics.EventLog/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==", + "path": "system.diagnostics.eventlog/6.0.0", + "hashPath": "system.diagnostics.eventlog.6.0.0.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.2.25": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qpkqDHLNxGR1qBNrdnnPfJFfsKSWy3nUELC/BWxP8vwSaf8vVwecZzXOV4B52yOGit94g0pLWJEe30a4L1tE7g==", + "path": "system.linq.dynamic.core/1.2.25", + "hashPath": "system.linq.dynamic.core.1.2.25.nupkg.sha512" + }, + "System.Reflection.Metadata/1.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==", + "path": "system.reflection.metadata/1.6.0", + "hashPath": "system.reflection.metadata.1.6.0.nupkg.sha512" + }, + "e-Suite.Modules.ContactsManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..50fb08e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.pdb new file mode 100644 index 0000000..135a014 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json new file mode 100644 index 0000000..a42fa34 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + { + "name": "Microsoft.AspNetCore.App", + "version": "8.0.0" + } + ], + "configProperties": { + "System.Reflection.NullabilityInfoContext.IsSupported": true, + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..f1a9899 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb new file mode 100644 index 0000000..a1ec9e8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.API.Common.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.API.Common.dll new file mode 100644 index 0000000..a4c898d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.API.Common.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Database.Audit.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Database.Audit.dll new file mode 100644 index 0000000..babcfae Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Database.Audit.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Database.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Database.Core.dll new file mode 100644 index 0000000..c92cc2b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Database.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Nuget.PasswordHasher.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Nuget.PasswordHasher.dll new file mode 100644 index 0000000..da0344a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Nuget.PasswordHasher.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.UnitTestCore.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.UnitTestCore.dll new file mode 100644 index 0000000..dbd5ed9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.UnitTestCore.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Utilities.Pagination.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Utilities.Pagination.dll new file mode 100644 index 0000000..3d3bd75 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/e-suite.Utilities.Pagination.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/eSuite.Core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/eSuite.Core.dll new file mode 100644 index 0000000..e977fe3 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/eSuite.Core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..d5a8c37 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..e548e68 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..e014e2d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..d2d34a9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..95ba380 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..fbd6f21 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..dca8640 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..388c3a8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..52ca0cc Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..a160e8c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..5aaa36b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..21e5f9a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..f1b2ec1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..95f5ff8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..e863878 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..9021665 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..1d3b394 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..773c01f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..dd242e2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..a6d1507 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..e1544b1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..b973f38 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..f35bfe7 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..eade81b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..e6e46b6 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.api.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.api.dll new file mode 100644 index 0000000..ffd41b5 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.api.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.core.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.core.dll new file mode 100644 index 0000000..6750450 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.core.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.dll new file mode 100644 index 0000000..029f779 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.engine.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.framework.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.framework.dll new file mode 100644 index 0000000..a4b0a95 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.framework.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.framework.legacy.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.framework.legacy.dll new file mode 100644 index 0000000..cc1c83a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/nunit.framework.legacy.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..8d2ec40 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..fc39387 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..65efdcd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..20e7c34 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..8fbbbf4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..3d0d41c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..64495e5 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..89213a1 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..7bea004 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..fd63906 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..aefa288 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..60fe8bb Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..d58604b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..a60916e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..905b81d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testcentric.engine.metadata.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testcentric.engine.metadata.dll new file mode 100644 index 0000000..b982b6b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testcentric.engine.metadata.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testhost.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testhost.dll new file mode 100644 index 0000000..1293868 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testhost.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testhost.exe b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testhost.exe new file mode 100644 index 0000000..28d7921 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/testhost.exe differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..d065beb Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..3ce4b68 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..0ae1f0a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..af9add9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..7b20360 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..3a8015b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..edf5098 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..f57eeba Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..352f693 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..56dd542 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll new file mode 100644 index 0000000..6880d0d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll new file mode 100644 index 0000000..2185e73 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll new file mode 100644 index 0000000..a5ba960 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll new file mode 100644 index 0000000..5ad986f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll new file mode 100644 index 0000000..15c99a7 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/bin/Debug/net8.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..ed92695 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/_IsIncrementalBuild b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/_IsIncrementalBuild new file mode 100644 index 0000000..9735daa --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/_IsIncrementalBuild @@ -0,0 +1 @@ +obj\Debug\net6.0\\_IsIncrementalBuild diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs new file mode 100644 index 0000000..e27dfdb --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-Suite.Modules.ContactsManager.UnitTests")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-Suite.Modules.ContactsManager.UnitTests")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-Suite.Modules.ContactsManager.UnitTests")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache new file mode 100644 index 0000000..b65bb49 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +55d6a6b2a1e9250319d2db474c2b67901cfa84648b66e7259d0cebb64322881e diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..219b3c2 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_Suite.Modules.ContactsManager.UnitTests +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.assets.cache new file mode 100644 index 0000000..09edcd7 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache new file mode 100644 index 0000000..e41608c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete new file mode 100644 index 0000000..e69de29 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..de8c551 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +d5644b8149e55d55b904aef964dd17ad5f3d7430 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.FileListAbsolute.txt b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..da83ffe --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.FileListAbsolute.txt @@ -0,0 +1,299 @@ +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\CoverletSourceRootsMapping +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\testhost.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\testhost.exe +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\NUnit3.TestAdapter.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\NUnit3.TestAdapter.pdb +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.engine.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.engine.api.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.engine.core.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\testcentric.engine.metadata.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.deps.json +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.pdb +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Database.Audit.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Database.Core.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.UnitTestCore.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\eSuite.Core.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Nuget.PasswordHasher.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.Cookies.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.Core.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Cryptography.Internal.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.DataProtection.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.DataProtection.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Hosting.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.Extensions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.Features.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Identity.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.WebUtilities.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.VisualStudio.CodeCoverage.Shim.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.EntityFrameworkCore.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.EntityFrameworkCore.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Caching.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Caching.Memory.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Configuration.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Configuration.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.DependencyInjection.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.FileProviders.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Hosting.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Identity.Core.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Logging.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Logging.Abstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.ObjectPool.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Options.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Primitives.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.WebEncoders.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Net.Http.Headers.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.CoreUtilities.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.PlatformAbstractions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.CommunicationUtilities.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.CrossPlatEngine.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.Utilities.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.VisualStudio.TestPlatform.Common.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Newtonsoft.Json.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\NuGet.Frameworks.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.framework.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Linq.Dynamic.Core.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Security.Cryptography.Pkcs.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Security.Cryptography.Xml.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Security.Permissions.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\runtimes\win\lib\netcoreapp2.1\System.Security.Cryptography.Pkcs.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\refint\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.pdb +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\ref\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\testhost.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\testcentric.engine.metadata.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\testhost.exe +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\NUnit3.TestAdapter.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\NUnit3.TestAdapter.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.engine.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.engine.api.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.engine.core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Castle.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Database.Audit.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Database.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.UnitTestCore.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\eSuite.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Nuget.PasswordHasher.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.Cookies.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Authentication.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Cryptography.Internal.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.DataProtection.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.DataProtection.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Hosting.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.Extensions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Http.Features.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.Identity.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.AspNetCore.WebUtilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.VisualStudio.CodeCoverage.Shim.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.EntityFrameworkCore.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.EntityFrameworkCore.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Caching.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Caching.Memory.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Configuration.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Configuration.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.DependencyInjection.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.FileProviders.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Hosting.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Identity.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Logging.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Logging.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.ObjectPool.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Options.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.Primitives.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Extensions.WebEncoders.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.Net.Http.Headers.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.CoreUtilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.PlatformAbstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.CommunicationUtilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.CrossPlatEngine.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.TestPlatform.Utilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Microsoft.VisualStudio.TestPlatform.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Moq.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\Newtonsoft.Json.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\NuGet.Frameworks.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\nunit.framework.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Diagnostics.EventLog.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Linq.Dynamic.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Security.Cryptography.Pkcs.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Security.Cryptography.Xml.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\System.Security.Permissions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\cs\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\de\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\es\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\fr\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\it\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ja\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ko\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pl\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\pt-BR\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\ru\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\tr\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hans\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\zh-Hant\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\runtimes\win\lib\net6.0\System.Diagnostics.EventLog.Messages.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\runtimes\win\lib\net6.0\System.Diagnostics.EventLog.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\runtimes\win\lib\netcoreapp2.1\System.Security.Cryptography.Pkcs.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\refint\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net6.0\ref\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.API.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net6.0\e-suite.Utilities.Pagination.dll diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..423f8c4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache new file mode 100644 index 0000000..d1e53f4 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache @@ -0,0 +1 @@ +801d5fa19c470dfea81f7fe8a6ee90a83566cf41 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.pdb new file mode 100644 index 0000000..a25eff6 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.UnitTests.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_1aa6d32e-9fc3-44ea-9068-136920088627.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_1aa6d32e-9fc3-44ea-9068-136920088627.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_1aa6d32e-9fc3-44ea-9068-136920088627.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_1aa6d32e-9fc3-44ea-9068-136920088627.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_1aa6d32e-9fc3-44ea-9068-136920088627.assets.cache new file mode 100644 index 0000000..c6fb5b2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_1aa6d32e-9fc3-44ea-9068-136920088627.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_24923f27-c3ec-463e-8fcc-c41b7771d3cd.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_24923f27-c3ec-463e-8fcc-c41b7771d3cd.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_24923f27-c3ec-463e-8fcc-c41b7771d3cd.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_24923f27-c3ec-463e-8fcc-c41b7771d3cd.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_24923f27-c3ec-463e-8fcc-c41b7771d3cd.assets.cache new file mode 100644 index 0000000..a224d22 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_24923f27-c3ec-463e-8fcc-c41b7771d3cd.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_45a7512f-6195-455a-86c8-51f26c4e2e03.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_45a7512f-6195-455a-86c8-51f26c4e2e03.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_45a7512f-6195-455a-86c8-51f26c4e2e03.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_45a7512f-6195-455a-86c8-51f26c4e2e03.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_45a7512f-6195-455a-86c8-51f26c4e2e03.assets.cache new file mode 100644 index 0000000..095eb55 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_45a7512f-6195-455a-86c8-51f26c4e2e03.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_4d4e56b6-6f4d-4e56-90ea-1470c12df3df.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_4d4e56b6-6f4d-4e56-90ea-1470c12df3df.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_4d4e56b6-6f4d-4e56-90ea-1470c12df3df.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_4d4e56b6-6f4d-4e56-90ea-1470c12df3df.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_4d4e56b6-6f4d-4e56-90ea-1470c12df3df.assets.cache new file mode 100644 index 0000000..b56eb50 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_4d4e56b6-6f4d-4e56-90ea-1470c12df3df.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_5bbfd957-4ad7-47d1-9b2b-f2f49e3abdd6.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_5bbfd957-4ad7-47d1-9b2b-f2f49e3abdd6.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_5bbfd957-4ad7-47d1-9b2b-f2f49e3abdd6.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_5bbfd957-4ad7-47d1-9b2b-f2f49e3abdd6.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_5bbfd957-4ad7-47d1-9b2b-f2f49e3abdd6.assets.cache new file mode 100644 index 0000000..c9287a4 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_5bbfd957-4ad7-47d1-9b2b-f2f49e3abdd6.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_6b74e34c-1d31-4a45-b67d-6fcd0df707a4.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_6b74e34c-1d31-4a45-b67d-6fcd0df707a4.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_6b74e34c-1d31-4a45-b67d-6fcd0df707a4.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_6b74e34c-1d31-4a45-b67d-6fcd0df707a4.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_6b74e34c-1d31-4a45-b67d-6fcd0df707a4.assets.cache new file mode 100644 index 0000000..5796c39 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_6b74e34c-1d31-4a45-b67d-6fcd0df707a4.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_7950ab9a-2ca4-473c-bfc1-069ad797df07.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_7950ab9a-2ca4-473c-bfc1-069ad797df07.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_7950ab9a-2ca4-473c-bfc1-069ad797df07.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_7950ab9a-2ca4-473c-bfc1-069ad797df07.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_7950ab9a-2ca4-473c-bfc1-069ad797df07.assets.cache new file mode 100644 index 0000000..214d471 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_7950ab9a-2ca4-473c-bfc1-069ad797df07.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9514d8aa-9e13-4790-975f-5f8eb984775c.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9514d8aa-9e13-4790-975f-5f8eb984775c.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9514d8aa-9e13-4790-975f-5f8eb984775c.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9514d8aa-9e13-4790-975f-5f8eb984775c.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9514d8aa-9e13-4790-975f-5f8eb984775c.assets.cache new file mode 100644 index 0000000..fd11d92 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9514d8aa-9e13-4790-975f-5f8eb984775c.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9a5447f1-c3ec-4163-a558-815da0dc6399.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9a5447f1-c3ec-4163-a558-815da0dc6399.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9a5447f1-c3ec-4163-a558-815da0dc6399.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9a5447f1-c3ec-4163-a558-815da0dc6399.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9a5447f1-c3ec-4163-a558-815da0dc6399.assets.cache new file mode 100644 index 0000000..91ff629 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9a5447f1-c3ec-4163-a558-815da0dc6399.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9d31cf12-b918-40e8-9c38-bb7cc6b2c10f.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9d31cf12-b918-40e8-9c38-bb7cc6b2c10f.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9d31cf12-b918-40e8-9c38-bb7cc6b2c10f.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9d31cf12-b918-40e8-9c38-bb7cc6b2c10f.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9d31cf12-b918-40e8-9c38-bb7cc6b2c10f.assets.cache new file mode 100644 index 0000000..5ab50f9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_9d31cf12-b918-40e8-9c38-bb7cc6b2c10f.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_a137ebed-e093-4c68-afcc-9addb15235f3.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_a137ebed-e093-4c68-afcc-9addb15235f3.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_a137ebed-e093-4c68-afcc-9addb15235f3.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_a137ebed-e093-4c68-afcc-9addb15235f3.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_a137ebed-e093-4c68-afcc-9addb15235f3.assets.cache new file mode 100644 index 0000000..b1acf5d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_a137ebed-e093-4c68-afcc-9addb15235f3.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_ba8b08cf-4bf3-4bfb-a070-9e1d3066a298.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_ba8b08cf-4bf3-4bfb-a070-9e1d3066a298.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_ba8b08cf-4bf3-4bfb-a070-9e1d3066a298.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_ba8b08cf-4bf3-4bfb-a070-9e1d3066a298.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_ba8b08cf-4bf3-4bfb-a070-9e1d3066a298.assets.cache new file mode 100644 index 0000000..e360abb Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_ba8b08cf-4bf3-4bfb-a070-9e1d3066a298.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c1f95443-8449-4612-ae44-33cfa668830c.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c1f95443-8449-4612-ae44-33cfa668830c.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c1f95443-8449-4612-ae44-33cfa668830c.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c1f95443-8449-4612-ae44-33cfa668830c.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c1f95443-8449-4612-ae44-33cfa668830c.assets.cache new file mode 100644 index 0000000..de4750b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c1f95443-8449-4612-ae44-33cfa668830c.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c81db9a9-6763-4c17-9963-8680bad4a085.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c81db9a9-6763-4c17-9963-8680bad4a085.assets.cache new file mode 100644 index 0000000..82461e8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_c81db9a9-6763-4c17-9963-8680bad4a085.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_d53b88e8-a45b-4969-a262-c0cc6b495023.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_d53b88e8-a45b-4969-a262-c0cc6b495023.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_d53b88e8-a45b-4969-a262-c0cc6b495023.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_d53b88e8-a45b-4969-a262-c0cc6b495023.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_d53b88e8-a45b-4969-a262-c0cc6b495023.assets.cache new file mode 100644 index 0000000..660c8d3 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_d53b88e8-a45b-4969-a262-c0cc6b495023.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_da5e639e-4ba0-461c-a3af-d394d5f07aa0.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_da5e639e-4ba0-461c-a3af-d394d5f07aa0.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_da5e639e-4ba0-461c-a3af-d394d5f07aa0.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_da5e639e-4ba0-461c-a3af-d394d5f07aa0.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_da5e639e-4ba0-461c-a3af-d394d5f07aa0.assets.cache new file mode 100644 index 0000000..003581e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_da5e639e-4ba0-461c-a3af-d394d5f07aa0.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_dac4ade5-0ed1-47a4-82a2-855379e35ccd.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_dac4ade5-0ed1-47a4-82a2-855379e35ccd.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_dac4ade5-0ed1-47a4-82a2-855379e35ccd.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_dac4ade5-0ed1-47a4-82a2-855379e35ccd.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_dac4ade5-0ed1-47a4-82a2-855379e35ccd.assets.cache new file mode 100644 index 0000000..c108b9c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_dac4ade5-0ed1-47a4-82a2-855379e35ccd.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_e429dce6-ecc2-4177-8c33-3da70de1712d.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_e429dce6-ecc2-4177-8c33-3da70de1712d.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_e429dce6-ecc2-4177-8c33-3da70de1712d.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_e429dce6-ecc2-4177-8c33-3da70de1712d.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_e429dce6-ecc2-4177-8c33-3da70de1712d.assets.cache new file mode 100644 index 0000000..99a997a Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/nCrunchTemp_e429dce6-ecc2-4177-8c33-3da70de1712d.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/ref/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/ref/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..7f106d3 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/ref/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/refint/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/refint/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..7f106d3 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net6.0/refint/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs new file mode 100644 index 0000000..e27dfdb --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-Suite.Modules.ContactsManager.UnitTests")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-Suite.Modules.ContactsManager.UnitTests")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-Suite.Modules.ContactsManager.UnitTests")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache new file mode 100644 index 0000000..b65bb49 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +55d6a6b2a1e9250319d2db474c2b67901cfa84648b66e7259d0cebb64322881e diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..698eaf6 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_Suite.Modules.ContactsManager.UnitTests +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.assets.cache new file mode 100644 index 0000000..fd92c08 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache new file mode 100644 index 0000000..a122f7f Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete new file mode 100644 index 0000000..e69de29 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..dd27117 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +29881bd42e7afdd1d7a3f5419cbfefa6d8d6c7bc90b676042a568a9374ed0b6c diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.FileListAbsolute.txt b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..81edb8f --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.csproj.FileListAbsolute.txt @@ -0,0 +1,116 @@ +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\CoverletSourceRootsMapping_e-Suite.Modules.ContactsManager.UnitTests +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\testhost.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\testhost.exe +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\NUnit3.TestAdapter.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\NUnit3.TestAdapter.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\nunit.engine.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\nunit.engine.api.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\nunit.engine.core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\testcentric.engine.metadata.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.runtimeconfig.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Castle.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-suite.API.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-suite.Database.Audit.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-suite.Database.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-suite.UnitTestCore.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-suite.Utilities.Pagination.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\eSuite.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-suite.Nuget.PasswordHasher.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.VisualStudio.CodeCoverage.Shim.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.EntityFrameworkCore.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.EntityFrameworkCore.Abstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.TestPlatform.CoreUtilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.TestPlatform.PlatformAbstractions.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.TestPlatform.CommunicationUtilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.TestPlatform.CrossPlatEngine.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.TestPlatform.Utilities.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Microsoft.VisualStudio.TestPlatform.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Moq.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\Newtonsoft.Json.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\NuGet.Frameworks.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\nunit.framework.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\nunit.framework.legacy.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\System.Linq.Dynamic.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\cs\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\cs\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\de\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\de\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\es\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\es\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\fr\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\fr\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\it\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\it\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ja\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ja\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ko\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ko\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pl\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pl\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pt-BR\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pt-BR\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ru\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ru\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\tr\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\tr\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hans\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hans\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hant\Microsoft.TestPlatform.CoreUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hant\Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\cs\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\cs\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\cs\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\de\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\de\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\de\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\es\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\es\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\es\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\fr\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\fr\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\fr\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\it\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\it\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\it\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ja\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ja\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ja\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ko\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ko\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ko\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pl\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pl\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pl\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pt-BR\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pt-BR\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\pt-BR\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ru\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ru\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\ru\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\tr\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\tr\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\tr\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hans\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hans\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hans\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hant\Microsoft.TestPlatform.CommunicationUtilities.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hant\Microsoft.TestPlatform.CrossPlatEngine.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\zh-Hant\Microsoft.VisualStudio.TestPlatform.Common.resources.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.sourcelink.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.csproj.CopyComplete +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\refint\e-Suite.Modules.ContactsManager.UnitTests.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager.UnitTests\obj\Debug\net8.0\ref\e-Suite.Modules.ContactsManager.UnitTests.dll diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..50fb08e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache new file mode 100644 index 0000000..bf00c5d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.genruntimeconfig.cache @@ -0,0 +1 @@ +d67199fe2e52272560f8148809065e9454e6823debbb44ab15580cfec8875fa2 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.pdb new file mode 100644 index 0000000..135a014 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.sourcelink.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.sourcelink.json new file mode 100644 index 0000000..8b82ea1 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.UnitTests.sourcelink.json @@ -0,0 +1 @@ +{"documents":{"C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\*":"https://sunbranding.visualstudio.com/e-suite/_apis/git/repositories/e-suite.Modules.ContactsManager/items?api-version=1.0&versionType=commit&version=16d1f8478732acedbaca8ba574c4168abdb09918&path=/*"}} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2967d259-3fc6-4c79-84ba-54def543c582.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2967d259-3fc6-4c79-84ba-54def543c582.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2967d259-3fc6-4c79-84ba-54def543c582.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2967d259-3fc6-4c79-84ba-54def543c582.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2967d259-3fc6-4c79-84ba-54def543c582.assets.cache new file mode 100644 index 0000000..a998e3b Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2967d259-3fc6-4c79-84ba-54def543c582.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2e36efd4-e9c4-48bf-8eac-2cf6d8f92cd5.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2e36efd4-e9c4-48bf-8eac-2cf6d8f92cd5.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2e36efd4-e9c4-48bf-8eac-2cf6d8f92cd5.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2e36efd4-e9c4-48bf-8eac-2cf6d8f92cd5.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2e36efd4-e9c4-48bf-8eac-2cf6d8f92cd5.assets.cache new file mode 100644 index 0000000..aba3fe9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_2e36efd4-e9c4-48bf-8eac-2cf6d8f92cd5.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_67b593c9-6678-4e8f-b833-f28ad347f659.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_67b593c9-6678-4e8f-b833-f28ad347f659.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_67b593c9-6678-4e8f-b833-f28ad347f659.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_67b593c9-6678-4e8f-b833-f28ad347f659.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_67b593c9-6678-4e8f-b833-f28ad347f659.assets.cache new file mode 100644 index 0000000..d2bd9a8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_67b593c9-6678-4e8f-b833-f28ad347f659.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_ae5e1cbf-b27d-454e-9cec-e091d4f903ab.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_ae5e1cbf-b27d-454e-9cec-e091d4f903ab.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_ae5e1cbf-b27d-454e-9cec-e091d4f903ab.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_ae5e1cbf-b27d-454e-9cec-e091d4f903ab.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_ae5e1cbf-b27d-454e-9cec-e091d4f903ab.assets.cache new file mode 100644 index 0000000..a1f68d9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_ae5e1cbf-b27d-454e-9cec-e091d4f903ab.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_baefcd42-31b9-4a93-b1f1-044c3e045a23.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_baefcd42-31b9-4a93-b1f1-044c3e045a23.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_baefcd42-31b9-4a93-b1f1-044c3e045a23.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_baefcd42-31b9-4a93-b1f1-044c3e045a23.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_baefcd42-31b9-4a93-b1f1-044c3e045a23.assets.cache new file mode 100644 index 0000000..87ea73d Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_baefcd42-31b9-4a93-b1f1-044c3e045a23.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_f383534c-bb00-44ab-8733-5fcdc1119aad.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_f383534c-bb00-44ab-8733-5fcdc1119aad.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_f383534c-bb00-44ab-8733-5fcdc1119aad.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_f383534c-bb00-44ab-8733-5fcdc1119aad.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_f383534c-bb00-44ab-8733-5fcdc1119aad.assets.cache new file mode 100644 index 0000000..5bd812e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/nCrunchTemp_f383534c-bb00-44ab-8733-5fcdc1119aad.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/ref/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/ref/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..8a09709 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/ref/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/refint/e-Suite.Modules.ContactsManager.UnitTests.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/refint/e-Suite.Modules.ContactsManager.UnitTests.dll new file mode 100644 index 0000000..8a09709 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/Debug/net8.0/refint/e-Suite.Modules.ContactsManager.UnitTests.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.dgspec.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.dgspec.json new file mode 100644 index 0000000..79bd7dc --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.dgspec.json @@ -0,0 +1,170 @@ +{ + "format": 1, + "restore": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj": {} + }, + "projects": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj", + "projectName": "e-Suite.Modules.ContactsManager.UnitTests", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\NuGet.Config", + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "Microsoft.NET.Test.Sdk": { + "target": "Package", + "version": "[17.6.0, )" + }, + "NUnit": { + "target": "Package", + "version": "[3.13.3, )" + }, + "NUnit3TestAdapter": { + "target": "Package", + "version": "[4.4.2, )" + }, + "coverlet.collector": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[6.0.0, )" + }, + "e-suite.Database.Core": { + "target": "Package", + "version": "[2023.5.23.1-beta, )" + }, + "e-suite.UnitTestCore": { + "target": "Package", + "version": "[2023.5.23.1-beta, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100\\RuntimeIdentifierGraph.json" + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "projectName": "e-Suite.Modules.ContactsManager", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\NuGet.Config", + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "e-suite.API.Common": { + "target": "Package", + "version": "[2023.5.23.21-beta, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.g.props b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.g.props new file mode 100644 index 0000000..c22ad5e --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.g.props @@ -0,0 +1,24 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\me\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages + PackageReference + 6.8.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.g.targets b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.g.targets new file mode 100644 index 0000000..2819000 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/e-Suite.Modules.ContactsManager.UnitTests.csproj.nuget.g.targets @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/project.assets.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/project.assets.json new file mode 100644 index 0000000..fec971a --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/project.assets.json @@ -0,0 +1,3343 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "Castle.Core/5.1.1": { + "type": "package", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + }, + "compile": { + "lib/net6.0/Castle.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Castle.Core.dll": { + "related": ".xml" + } + } + }, + "coverlet.collector/6.0.0": { + "type": "package", + "build": { + "build/netstandard1.0/coverlet.collector.targets": {} + } + }, + "e-suite.API.Common/2023.5.23.21-beta": { + "type": "package", + "dependencies": { + "e-suite.Database.Core": "2023.5.23.1-beta", + "e-suite.Utilities.Pagination": "2023.5.16.1-beta", + "eSuite.Core": "2023.3.31.1-beta" + }, + "compile": { + "lib/net6.0/e-suite.API.Common.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.API.Common.dll": {} + } + }, + "e-suite.Database.Audit/2023.5.23.1-beta": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.3", + "Newtonsoft.Json": "13.0.2", + "System.Linq.Dynamic.Core": "1.2.25", + "eSuite.Core": "2023.3.31.1-beta" + }, + "compile": { + "lib/net6.0/e-suite.Database.Audit.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Database.Audit.dll": {} + } + }, + "e-suite.Database.Core/2023.5.23.1-beta": { + "type": "package", + "dependencies": { + "e-suite.Database.Audit": "2023.5.23.1-beta", + "e_suite.Nuget.PasswordHasher": "2022.12.1.1" + }, + "compile": { + "lib/net6.0/e-suite.Database.Core.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Database.Core.dll": {} + } + }, + "e-suite.UnitTestCore/2023.5.23.1-beta": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Moq": "4.18.4", + "e-suite.Database.Core": "2023.5.23.1-beta", + "eSuite.Core": "2023.3.31.1-beta" + }, + "compile": { + "lib/net6.0/e-suite.UnitTestCore.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.UnitTestCore.dll": {} + } + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.5" + }, + "compile": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": {} + } + }, + "eSuite.Core/2023.3.31.1-beta": { + "type": "package", + "compile": { + "lib/net6.0/eSuite.Core.dll": {} + }, + "runtime": { + "lib/net6.0/eSuite.Core.dll": {} + } + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Identity": "2.2.0" + }, + "compile": { + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll": {} + } + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication.Core": "2.2.0", + "Microsoft.AspNetCore.DataProtection": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "Microsoft.Extensions.WebEncoders": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0" + }, + "compile": { + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0", + "Microsoft.AspNetCore.DataProtection.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "Microsoft.Win32.Registry": "4.5.0", + "System.Security.Cryptography.Xml": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Hosting.Server.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Hosting.Abstractions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.AspNetCore.WebUtilities": "2.2.0", + "Microsoft.Extensions.ObjectPool": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "Microsoft.Net.Http.Headers": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Buffers": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication.Cookies": "2.2.0", + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.Identity.Core": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll": { + "related": ".xml" + } + } + }, + "Microsoft.CodeCoverage/17.6.0": { + "type": "package", + "compile": { + "lib/netcoreapp3.1/Microsoft.VisualStudio.CodeCoverage.Shim.dll": {} + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.VisualStudio.CodeCoverage.Shim.dll": {} + }, + "build": { + "build/netstandard2.0/Microsoft.CodeCoverage.props": {}, + "build/netstandard2.0/Microsoft.CodeCoverage.targets": {} + } + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.5", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.5", + "Microsoft.Extensions.Caching.Memory": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props": {} + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": { + "type": "package", + "compile": { + "lib/netstandard2.0/_._": {} + }, + "runtime": { + "lib/netstandard2.0/_._": {} + } + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Abstractions/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.Extensions.Logging": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "System.ComponentModel.Annotations": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets": {} + } + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0", + "System.Buffers": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NET.Test.Sdk/17.6.0": { + "type": "package", + "dependencies": { + "Microsoft.CodeCoverage": "17.6.0", + "Microsoft.TestPlatform.TestHost": "17.6.0" + }, + "compile": { + "lib/netcoreapp3.1/_._": {} + }, + "runtime": { + "lib/netcoreapp3.1/_._": {} + }, + "build": { + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.props": {}, + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.targets": {} + }, + "buildMultiTargeting": { + "buildMultiTargeting/Microsoft.NET.Test.Sdk.props": {} + } + }, + "Microsoft.NETCore.Platforms/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.TestPlatform.ObjectModel/17.6.0": { + "type": "package", + "dependencies": { + "NuGet.Frameworks": "5.11.0", + "System.Reflection.Metadata": "1.6.0" + }, + "compile": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll": {}, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll": {} + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll": {}, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll": {} + }, + "resource": { + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.TestPlatform.TestHost/17.6.0": { + "type": "package", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.6.0", + "Newtonsoft.Json": "13.0.1" + }, + "compile": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CommunicationUtilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.CrossPlatEngine.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.Utilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.Common.dll": {}, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll": {}, + "lib/netcoreapp3.1/testhost.dll": { + "related": ".deps.json" + } + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.TestPlatform.CommunicationUtilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.CrossPlatEngine.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll": {}, + "lib/netcoreapp3.1/Microsoft.TestPlatform.Utilities.dll": {}, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.Common.dll": {}, + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll": {}, + "lib/netcoreapp3.1/testhost.dll": { + "related": ".deps.json" + } + }, + "resource": { + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "cs" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "de" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "es" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "fr" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "it" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ja" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ko" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "pl" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "pt-BR" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "ru" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "tr" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll": { + "locale": "zh-Hant" + }, + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll": { + "locale": "zh-Hant" + } + }, + "build": { + "build/netcoreapp3.1/Microsoft.TestPlatform.TestHost.props": {} + } + }, + "Microsoft.Win32.Registry/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": {} + }, + "runtimeTargets": { + "runtimes/unix/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "Moq/4.18.4": { + "type": "package", + "dependencies": { + "Castle.Core": "5.1.1" + }, + "compile": { + "lib/net6.0/Moq.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Moq.dll": { + "related": ".xml" + } + } + }, + "NETStandard.Library/2.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + }, + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + }, + "build": { + "build/netstandard2.0/NETStandard.Library.targets": {} + } + }, + "Newtonsoft.Json/13.0.2": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "NuGet.Frameworks/5.11.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/NuGet.Frameworks.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NuGet.Frameworks.dll": { + "related": ".xml" + } + } + }, + "NUnit/3.13.3": { + "type": "package", + "dependencies": { + "NETStandard.Library": "2.0.0" + }, + "compile": { + "lib/netstandard2.0/nunit.framework.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/nunit.framework.dll": { + "related": ".xml" + } + }, + "build": { + "build/NUnit.props": {} + } + }, + "NUnit3TestAdapter/4.4.2": { + "type": "package", + "build": { + "build/netcoreapp3.1/NUnit3TestAdapter.props": {} + } + }, + "System.Buffers/4.5.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.ComponentModel.Annotations/4.5.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Diagnostics.EventLog/6.0.0": { + "type": "package", + "compile": { + "lib/net6.0/System.Diagnostics.EventLog.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Diagnostics.EventLog.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + }, + "runtimeTargets": { + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll": { + "assetType": "runtime", + "rid": "win" + }, + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Linq.Dynamic.Core/1.2.25": { + "type": "package", + "compile": { + "lib/net6.0/System.Linq.Dynamic.Core.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/System.Linq.Dynamic.Core.dll": { + "related": ".pdb;.xml" + } + } + }, + "System.Reflection.Metadata/1.6.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/System.Reflection.Metadata.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Reflection.Metadata.dll": { + "related": ".xml" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "compile": { + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + } + }, + "System.Security.AccessControl/4.5.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": {} + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Cryptography.Cng/4.5.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll": {} + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Cryptography.Pkcs/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.Cryptography.Cng": "4.5.0" + }, + "compile": { + "ref/netcoreapp2.1/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": {} + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Cryptography.Xml/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.Cryptography.Pkcs": "4.5.0", + "System.Security.Permissions": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.Cryptography.Xml.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Cryptography.Xml.dll": {} + } + }, + "System.Security.Permissions/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.Permissions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Permissions.dll": {} + } + }, + "System.Security.Principal.Windows/4.5.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": {} + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Text.Encodings.Web/4.5.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/System.Text.Encodings.Web.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Text.Encodings.Web.dll": { + "related": ".xml" + } + } + }, + "e-Suite.Modules.ContactsManager/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v6.0", + "dependencies": { + "e-suite.API.Common": "2023.5.23.21-beta" + }, + "compile": { + "bin/placeholder/e-Suite.Modules.ContactsManager.dll": {} + }, + "runtime": { + "bin/placeholder/e-Suite.Modules.ContactsManager.dll": {} + } + } + } + }, + "libraries": { + "Castle.Core/5.1.1": { + "sha512": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "type": "package", + "path": "castle.core/5.1.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ASL - Apache Software Foundation License.txt", + "CHANGELOG.md", + "LICENSE", + "castle-logo.png", + "castle.core.5.1.1.nupkg.sha512", + "castle.core.nuspec", + "lib/net462/Castle.Core.dll", + "lib/net462/Castle.Core.xml", + "lib/net6.0/Castle.Core.dll", + "lib/net6.0/Castle.Core.xml", + "lib/netstandard2.0/Castle.Core.dll", + "lib/netstandard2.0/Castle.Core.xml", + "lib/netstandard2.1/Castle.Core.dll", + "lib/netstandard2.1/Castle.Core.xml", + "readme.txt" + ] + }, + "coverlet.collector/6.0.0": { + "sha512": "tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ==", + "type": "package", + "path": "coverlet.collector/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/netstandard1.0/Microsoft.Bcl.AsyncInterfaces.dll", + "build/netstandard1.0/Microsoft.CSharp.dll", + "build/netstandard1.0/Microsoft.DotNet.PlatformAbstractions.dll", + "build/netstandard1.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "build/netstandard1.0/Microsoft.Extensions.DependencyInjection.dll", + "build/netstandard1.0/Microsoft.Extensions.DependencyModel.dll", + "build/netstandard1.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "build/netstandard1.0/Microsoft.TestPlatform.CoreUtilities.dll", + "build/netstandard1.0/Microsoft.TestPlatform.PlatformAbstractions.dll", + "build/netstandard1.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll", + "build/netstandard1.0/Mono.Cecil.Mdb.dll", + "build/netstandard1.0/Mono.Cecil.Pdb.dll", + "build/netstandard1.0/Mono.Cecil.Rocks.dll", + "build/netstandard1.0/Mono.Cecil.dll", + "build/netstandard1.0/Newtonsoft.Json.dll", + "build/netstandard1.0/NuGet.Frameworks.dll", + "build/netstandard1.0/System.AppContext.dll", + "build/netstandard1.0/System.Collections.Immutable.dll", + "build/netstandard1.0/System.Dynamic.Runtime.dll", + "build/netstandard1.0/System.IO.FileSystem.Primitives.dll", + "build/netstandard1.0/System.Linq.Expressions.dll", + "build/netstandard1.0/System.Linq.dll", + "build/netstandard1.0/System.ObjectModel.dll", + "build/netstandard1.0/System.Reflection.Emit.ILGeneration.dll", + "build/netstandard1.0/System.Reflection.Emit.Lightweight.dll", + "build/netstandard1.0/System.Reflection.Emit.dll", + "build/netstandard1.0/System.Reflection.Metadata.dll", + "build/netstandard1.0/System.Reflection.TypeExtensions.dll", + "build/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "build/netstandard1.0/System.Runtime.Serialization.Primitives.dll", + "build/netstandard1.0/System.Text.RegularExpressions.dll", + "build/netstandard1.0/System.Threading.Tasks.Extensions.dll", + "build/netstandard1.0/System.Threading.dll", + "build/netstandard1.0/System.Xml.ReaderWriter.dll", + "build/netstandard1.0/System.Xml.XDocument.dll", + "build/netstandard1.0/coverlet.collector.deps.json", + "build/netstandard1.0/coverlet.collector.dll", + "build/netstandard1.0/coverlet.collector.pdb", + "build/netstandard1.0/coverlet.collector.targets", + "build/netstandard1.0/coverlet.core.dll", + "build/netstandard1.0/coverlet.core.pdb", + "coverlet-icon.png", + "coverlet.collector.6.0.0.nupkg.sha512", + "coverlet.collector.nuspec" + ] + }, + "e-suite.API.Common/2023.5.23.21-beta": { + "sha512": "1867Fbx3Dc1fQSFC+oIBrJhb4xGy/oEX4b4Gx6efM9DPE3pzeulid0kNHv7UqBeaL6phdrsUyQu8lYrl2oYWgg==", + "type": "package", + "path": "e-suite.api.common/2023.5.23.21-beta", + "files": [ + ".nupkg.metadata", + "e-suite.api.common.2023.5.23.21-beta.nupkg.sha512", + "e-suite.api.common.nuspec", + "lib/net6.0/e-suite.API.Common.dll" + ] + }, + "e-suite.Database.Audit/2023.5.23.1-beta": { + "sha512": "8hM32LonYDw5fVS3KGR++vwmcgZgglMIjDF9apcy6Vz8HQEsrHd9lxvDT4U73bJBIyA34PIB+ioGiU4Q7uMxsw==", + "type": "package", + "path": "e-suite.database.audit/2023.5.23.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.database.audit.2023.5.23.1-beta.nupkg.sha512", + "e-suite.database.audit.nuspec", + "lib/net6.0/e-suite.Database.Audit.dll" + ] + }, + "e-suite.Database.Core/2023.5.23.1-beta": { + "sha512": "MpJA6iksaykv8HbXp4ZhGlezUvTlFv7RRCUmTRO6lxNF6BMK9lLeJEskaV4ivldNx4VPrvD1NINrjRR6ZDb9XQ==", + "type": "package", + "path": "e-suite.database.core/2023.5.23.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.database.core.2023.5.23.1-beta.nupkg.sha512", + "e-suite.database.core.nuspec", + "lib/net6.0/e-suite.Database.Core.dll" + ] + }, + "e-suite.UnitTestCore/2023.5.23.1-beta": { + "sha512": "XRj4+JmRyN7nZZ6ZakwOgU75zIv58tCZ5xe4g6TVQlvQ/fh9PvZ4ugQDlQg743yem0zDHkdW/+75gd6unHP4ng==", + "type": "package", + "path": "e-suite.unittestcore/2023.5.23.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.unittestcore.2023.5.23.1-beta.nupkg.sha512", + "e-suite.unittestcore.nuspec", + "lib/net6.0/e-suite.UnitTestCore.dll" + ] + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "sha512": "0k9sjGp9YZpRUQaiyBkQpmslJTMOJ7ZR/f8Latc02Amcw953pB//CN+/XGGOO09FuxA3cWIsDQ9WsSEVU9iwxg==", + "type": "package", + "path": "e-suite.utilities.pagination/2023.5.16.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.utilities.pagination.2023.5.16.1-beta.nupkg.sha512", + "e-suite.utilities.pagination.nuspec", + "lib/net6.0/e-suite.Utilities.Pagination.dll" + ] + }, + "eSuite.Core/2023.3.31.1-beta": { + "sha512": "U1cmpMvZwNHk72F6C1r6ZEVuXVQDj10PxRGGG3g5iDWoGDEyCTImtKnZ4V2N/SesmZ87PCYrPsZdfVvjbHlJGA==", + "type": "package", + "path": "esuite.core/2023.3.31.1-beta", + "files": [ + ".nupkg.metadata", + "esuite.core.2023.3.31.1-beta.nupkg.sha512", + "esuite.core.nuspec", + "lib/net6.0/eSuite.Core.dll" + ] + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "sha512": "oKt0q1UISYgWj9v72yIEhvYkcdHiw8SNIQUkE+DZJ1FuVkCqPknzMiFIZY3FKGZOQf0XY1pgccazZPyl+06VWQ==", + "type": "package", + "path": "e_suite.nuget.passwordhasher/2022.12.1.1", + "files": [ + ".nupkg.metadata", + "e_suite.nuget.passwordhasher.2022.12.1.1.nupkg.sha512", + "e_suite.nuget.passwordhasher.nuspec", + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll" + ] + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "sha512": "b0R9X7L6zMqNsssKDvhYHuNi5x0s4DyHTeXybIAyGaitKiW1Q5aAGKdV2codHPiePv9yHfC9hAMyScXQ/xXhPw==", + "type": "package", + "path": "microsoft.aspnetcore.authentication/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.xml", + "microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.nuspec" + ] + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "sha512": "VloMLDJMf3n/9ic5lCBOa42IBYJgyB1JhzLsL68Zqg+2bEPWfGBj/xCJy/LrKTArN0coOcZp3wyVTZlx0y9pHQ==", + "type": "package", + "path": "microsoft.aspnetcore.authentication.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.xml", + "microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "sha512": "Iar9VFlBHkZGdSG9ZUTmn6Q8Qg+6CtW5G/TyJI2F8B432TOH+nZlkU7O0W0byow6xsxqOYeTviSHz4cCJ3amfQ==", + "type": "package", + "path": "microsoft.aspnetcore.authentication.cookies/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.xml", + "microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.cookies.nuspec" + ] + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "sha512": "XlVJzJ5wPOYW+Y0J6Q/LVTEyfS4ssLXmt60T0SPP+D8abVhBTl+cgw2gDHlyKYIkcJg7btMVh383NDkMVqD/fg==", + "type": "package", + "path": "microsoft.aspnetcore.authentication.core/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.xml", + "microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.core.nuspec" + ] + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "sha512": "GXmMD8/vuTLPLvKzKEPz/4vapC5e0cwx1tUVd83ePRyWF9CCrn/pg4/1I+tGkQqFLPvi3nlI2QtPtC6MQN8Nww==", + "type": "package", + "path": "microsoft.aspnetcore.cryptography.internal/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.xml", + "microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.cryptography.internal.nuspec" + ] + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "sha512": "NCY0PH3nrFYbhqiq72rwWsUXlV4OAE0MOukvGvIBOTnEPMC1yVL42k1DXLnaIu+c0yfMAxIIG9Iuaykp9BQQQw==", + "type": "package", + "path": "microsoft.aspnetcore.cryptography.keyderivation/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll", + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.xml", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.xml", + "microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.cryptography.keyderivation.nuspec" + ] + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "sha512": "G6dvu5Nd2vjpYbzazZ//qBFbSEf2wmBUbyAR7E4AwO3gWjhoJD5YxpThcGJb7oE3VUcW65SVMXT+cPCiiBg8Sg==", + "type": "package", + "path": "microsoft.aspnetcore.dataprotection/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.xml", + "microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.dataprotection.nuspec" + ] + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "sha512": "seANFXmp8mb5Y12m1ShiElJ3ZdOT3mBN3wA1GPhHJIvZ/BxOCPyqEOR+810OWsxEZwA5r5fDRNpG/CqiJmQnJg==", + "type": "package", + "path": "microsoft.aspnetcore.dataprotection.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.xml", + "microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.dataprotection.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "sha512": "ubycklv+ZY7Kutdwuy1W4upWcZ6VFR8WUXU7l7B2+mvbDBBPAcfpi+E+Y5GFe+Q157YfA3C49D2GCjAZc7Mobw==", + "type": "package", + "path": "microsoft.aspnetcore.hosting.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.xml", + "microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.hosting.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "sha512": "1PMijw8RMtuQF60SsD/JlKtVfvh4NORAhF4wjysdABhlhTrYmtgssqyncR0Stq5vqtjplZcj6kbT4LRTglt9IQ==", + "type": "package", + "path": "microsoft.aspnetcore.hosting.server.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.xml", + "microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.hosting.server.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "sha512": "YogBSMotWPAS/X5967pZ+yyWPQkThxhmzAwyCHCSSldzYBkW5W5d6oPfBaPqQOnSHYTpSOSOkpZoAce0vwb6+A==", + "type": "package", + "path": "microsoft.aspnetcore.http/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.xml", + "microsoft.aspnetcore.http.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.nuspec" + ] + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "sha512": "Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==", + "type": "package", + "path": "microsoft.aspnetcore.http.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.xml", + "microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "sha512": "2DgZ9rWrJtuR7RYiew01nGRzuQBDaGHGmK56Rk54vsLLsCdzuFUPqbDTJCS1qJQWTbmbIQ9wGIOjpxA1t0l7/w==", + "type": "package", + "path": "microsoft.aspnetcore.http.extensions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.xml", + "microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.extensions.nuspec" + ] + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "sha512": "ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==", + "type": "package", + "path": "microsoft.aspnetcore.http.features/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.xml", + "microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.features.nuspec" + ] + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "sha512": "F16BKeS96wKhyIyhaFR7m8kRIwIvPUW9Dx7IlGWmu2IIwnUDCdo+2z7IrWKA8r77pZQ1UE9kYcBPg5456YdAIA==", + "type": "package", + "path": "microsoft.aspnetcore.identity/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.xml", + "microsoft.aspnetcore.identity.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.identity.nuspec" + ] + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "sha512": "9ErxAAKaDzxXASB/b5uLEkLgUWv1QbeVxyJYEHQwMaxXOeFFVkQxiq8RyfVcifLU7NR0QY0p3acqx4ZpYfhHDg==", + "type": "package", + "path": "microsoft.aspnetcore.webutilities/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.xml", + "microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.webutilities.nuspec" + ] + }, + "Microsoft.CodeCoverage/17.6.0": { + "sha512": "5v2GwzpR7JEuQUzupjx3zLwn2FutADW/weLzLt726DR3WXxsM+ICPoJG6pxuKFsumtZp890UrVuudTUhsE8Qyg==", + "type": "package", + "path": "microsoft.codecoverage/17.6.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE_NET.txt", + "ThirdPartyNotices.txt", + "build/netstandard2.0/CodeCoverage/CodeCoverage.config", + "build/netstandard2.0/CodeCoverage/CodeCoverage.exe", + "build/netstandard2.0/CodeCoverage/VanguardInstrumentationProfiler_x86.config", + "build/netstandard2.0/CodeCoverage/amd64/CodeCoverage.exe", + "build/netstandard2.0/CodeCoverage/amd64/VanguardInstrumentationProfiler_x64.config", + "build/netstandard2.0/CodeCoverage/amd64/covrun64.dll", + "build/netstandard2.0/CodeCoverage/amd64/msdia140.dll", + "build/netstandard2.0/CodeCoverage/arm64/VanguardInstrumentationProfiler_arm64.config", + "build/netstandard2.0/CodeCoverage/arm64/covrunarm64.dll", + "build/netstandard2.0/CodeCoverage/arm64/msdia140.dll", + "build/netstandard2.0/CodeCoverage/codecoveragemessages.dll", + "build/netstandard2.0/CodeCoverage/coreclr/Microsoft.VisualStudio.CodeCoverage.Shim.dll", + "build/netstandard2.0/CodeCoverage/covrun32.dll", + "build/netstandard2.0/CodeCoverage/msdia140.dll", + "build/netstandard2.0/InstrumentationEngine/alpine/x64/VanguardInstrumentationProfiler_x64.config", + "build/netstandard2.0/InstrumentationEngine/alpine/x64/libCoverageInstrumentationMethod.so", + "build/netstandard2.0/InstrumentationEngine/alpine/x64/libInstrumentationEngine.so", + "build/netstandard2.0/InstrumentationEngine/arm64/MicrosoftInstrumentationEngine_arm64.dll", + "build/netstandard2.0/InstrumentationEngine/macos/x64/VanguardInstrumentationProfiler_x64.config", + "build/netstandard2.0/InstrumentationEngine/macos/x64/libCoverageInstrumentationMethod.dylib", + "build/netstandard2.0/InstrumentationEngine/macos/x64/libInstrumentationEngine.dylib", + "build/netstandard2.0/InstrumentationEngine/ubuntu/x64/VanguardInstrumentationProfiler_x64.config", + "build/netstandard2.0/InstrumentationEngine/ubuntu/x64/libCoverageInstrumentationMethod.so", + "build/netstandard2.0/InstrumentationEngine/ubuntu/x64/libInstrumentationEngine.so", + "build/netstandard2.0/InstrumentationEngine/x64/MicrosoftInstrumentationEngine_x64.dll", + "build/netstandard2.0/InstrumentationEngine/x86/MicrosoftInstrumentationEngine_x86.dll", + "build/netstandard2.0/Microsoft.CodeCoverage.Core.dll", + "build/netstandard2.0/Microsoft.CodeCoverage.Instrumentation.dll", + "build/netstandard2.0/Microsoft.CodeCoverage.Interprocess.dll", + "build/netstandard2.0/Microsoft.CodeCoverage.props", + "build/netstandard2.0/Microsoft.CodeCoverage.targets", + "build/netstandard2.0/Microsoft.DiaSymReader.dll", + "build/netstandard2.0/Microsoft.VisualStudio.TraceDataCollector.dll", + "build/netstandard2.0/Mono.Cecil.Pdb.dll", + "build/netstandard2.0/Mono.Cecil.Rocks.dll", + "build/netstandard2.0/Mono.Cecil.dll", + "build/netstandard2.0/ThirdPartyNotices.txt", + "build/netstandard2.0/cs/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/de/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/es/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/fr/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/it/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/ja/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/ko/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/pl/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/pt-BR/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/ru/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/tr/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/zh-Hans/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "build/netstandard2.0/zh-Hant/Microsoft.VisualStudio.TraceDataCollector.resources.dll", + "lib/net462/Microsoft.VisualStudio.CodeCoverage.Shim.dll", + "lib/netcoreapp3.1/Microsoft.VisualStudio.CodeCoverage.Shim.dll", + "microsoft.codecoverage.17.6.0.nupkg.sha512", + "microsoft.codecoverage.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "sha512": "RXbRLHHWP2Z3pq8qcL5nQ6LPeoOyp8hasM5bd0Te8PiQi3RjWQR4tcbdY5XMqQ+oTO9wA8/RLhZRn/hnxlTDnQ==", + "type": "package", + "path": "microsoft.entityframeworkcore/7.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props", + "lib/net6.0/Microsoft.EntityFrameworkCore.dll", + "lib/net6.0/Microsoft.EntityFrameworkCore.xml", + "microsoft.entityframeworkcore.7.0.5.nupkg.sha512", + "microsoft.entityframeworkcore.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "sha512": "iwQso+hFRsEWjhH2WsEQj1D2QE5BlEXiXEt6A3SlYTPRPdZsyTNDeDDEdtxL+H/UJPQgQYY+9SMMRcEiXBmCAA==", + "type": "package", + "path": "microsoft.entityframeworkcore.abstractions/7.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll", + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.xml", + "microsoft.entityframeworkcore.abstractions.7.0.5.nupkg.sha512", + "microsoft.entityframeworkcore.abstractions.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": { + "sha512": "yMLM/aK1MikVqpjxd7PJ1Pjgztd3VAd26ZHxyjxG3RPeM9cHjvS5tCg9kAAayR6eHmBg0ffZsHdT28WfA5tTlA==", + "type": "package", + "path": "microsoft.entityframeworkcore.analyzers/7.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "analyzers/dotnet/cs/Microsoft.EntityFrameworkCore.Analyzers.dll", + "lib/netstandard2.0/_._", + "microsoft.entityframeworkcore.analyzers.7.0.5.nupkg.sha512", + "microsoft.entityframeworkcore.analyzers.nuspec" + ] + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "sha512": "IeimUd0TNbhB4ded3AbgBLQv2SnsiVugDyGV1MvspQFVlA07nDC7Zul7kcwH5jWN3JiTcp/ySE83AIJo8yfKjg==", + "type": "package", + "path": "microsoft.extensions.caching.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.xml", + "microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.caching.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "sha512": "xpidBs2KCE2gw1JrD0quHE72kvCaI3xFql5/Peb2GRtUuZX+dYPoK/NTdVMiM67Svym0M0Df9A3xyU0FbMQhHw==", + "type": "package", + "path": "microsoft.extensions.caching.memory/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Memory.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Memory.targets", + "lib/net462/Microsoft.Extensions.Caching.Memory.dll", + "lib/net462/Microsoft.Extensions.Caching.Memory.xml", + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net6.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/net7.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net7.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.xml", + "microsoft.extensions.caching.memory.7.0.0.nupkg.sha512", + "microsoft.extensions.caching.memory.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration/7.0.0": { + "sha512": "tldQUBWt/xeH2K7/hMPPo5g8zuLc3Ro9I5d4o/XrxvxOCA2EZBtW7bCHHTc49fcBtvB8tLAb/Qsmfrq+2SJ4vA==", + "type": "package", + "path": "microsoft.extensions.configuration/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.targets", + "lib/net462/Microsoft.Extensions.Configuration.dll", + "lib/net462/Microsoft.Extensions.Configuration.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.xml", + "microsoft.extensions.configuration.7.0.0.nupkg.sha512", + "microsoft.extensions.configuration.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Abstractions/7.0.0": { + "sha512": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==", + "type": "package", + "path": "microsoft.extensions.configuration.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "microsoft.extensions.configuration.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.configuration.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "sha512": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.targets", + "lib/net462/Microsoft.Extensions.DependencyInjection.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.xml", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.xml", + "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512", + "microsoft.extensions.dependencyinjection.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "sha512": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.dependencyinjection.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "sha512": "EcnaSsPTqx2MGnHrmWOD0ugbuuqVT8iICqSqPzi45V5/MA1LjUNb0kwgcxBGqizV1R+WeBK7/Gw25Jzkyk9bIw==", + "type": "package", + "path": "microsoft.extensions.fileproviders.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.xml", + "microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512", + "microsoft.extensions.fileproviders.abstractions.nuspec" + ] + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "sha512": "+k4AEn68HOJat5gj1TWa6X28WlirNQO9sPIIeQbia+91n03esEtMSSoekSTpMjUzjqtJWQN3McVx0GvSPFHF/Q==", + "type": "package", + "path": "microsoft.extensions.hosting.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.xml", + "microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512", + "microsoft.extensions.hosting.abstractions.nuspec" + ] + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "sha512": "/C+Valwg8IeUwDIunusittHivA9iyf82Jr1yeUFWO2zH2mDMMeYgjRyDLZqfL/7Vq94PEQsgv1XAaDfAX8msMw==", + "type": "package", + "path": "microsoft.extensions.identity.core/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll", + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.xml", + "microsoft.extensions.identity.core.2.2.0.nupkg.sha512", + "microsoft.extensions.identity.core.nuspec" + ] + }, + "Microsoft.Extensions.Logging/7.0.0": { + "sha512": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "type": "package", + "path": "microsoft.extensions.logging/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Logging.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.targets", + "lib/net462/Microsoft.Extensions.Logging.dll", + "lib/net462/Microsoft.Extensions.Logging.xml", + "lib/net6.0/Microsoft.Extensions.Logging.dll", + "lib/net6.0/Microsoft.Extensions.Logging.xml", + "lib/net7.0/Microsoft.Extensions.Logging.dll", + "lib/net7.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.1/Microsoft.Extensions.Logging.xml", + "microsoft.extensions.logging.7.0.0.nupkg.sha512", + "microsoft.extensions.logging.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "sha512": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "sha512": "gA8H7uQOnM5gb+L0uTNjViHYr+hRDqCdfugheGo/MxQnuHzmhhzCBTIPm19qL1z1Xe0NEMabfcOBGv9QghlZ8g==", + "type": "package", + "path": "microsoft.extensions.objectpool/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll", + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.xml", + "microsoft.extensions.objectpool.2.2.0.nupkg.sha512", + "microsoft.extensions.objectpool.nuspec" + ] + }, + "Microsoft.Extensions.Options/7.0.0": { + "sha512": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "type": "package", + "path": "microsoft.extensions.options/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Options.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Options.targets", + "lib/net462/Microsoft.Extensions.Options.dll", + "lib/net462/Microsoft.Extensions.Options.xml", + "lib/net6.0/Microsoft.Extensions.Options.dll", + "lib/net6.0/Microsoft.Extensions.Options.xml", + "lib/net7.0/Microsoft.Extensions.Options.dll", + "lib/net7.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.0/Microsoft.Extensions.Options.dll", + "lib/netstandard2.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.1/Microsoft.Extensions.Options.dll", + "lib/netstandard2.1/Microsoft.Extensions.Options.xml", + "microsoft.extensions.options.7.0.0.nupkg.sha512", + "microsoft.extensions.options.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "sha512": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==", + "type": "package", + "path": "microsoft.extensions.primitives/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Primitives.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Primitives.targets", + "lib/net462/Microsoft.Extensions.Primitives.dll", + "lib/net462/Microsoft.Extensions.Primitives.xml", + "lib/net6.0/Microsoft.Extensions.Primitives.dll", + "lib/net6.0/Microsoft.Extensions.Primitives.xml", + "lib/net7.0/Microsoft.Extensions.Primitives.dll", + "lib/net7.0/Microsoft.Extensions.Primitives.xml", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.dll", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.xml", + "microsoft.extensions.primitives.7.0.0.nupkg.sha512", + "microsoft.extensions.primitives.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "sha512": "V8XcqYcpcdBAxUhLeyYcuKmxu4CtNQA9IphTnARpQGhkop4A93v2XgM3AtaVVJo3H2cDWxWM6aeO8HxkifREqw==", + "type": "package", + "path": "microsoft.extensions.webencoders/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll", + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.xml", + "microsoft.extensions.webencoders.2.2.0.nupkg.sha512", + "microsoft.extensions.webencoders.nuspec" + ] + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "sha512": "iZNkjYqlo8sIOI0bQfpsSoMTmB/kyvmV2h225ihyZT33aTp48ZpF6qYnXxzSXmHt8DpBAwBTX+1s1UFLbYfZKg==", + "type": "package", + "path": "microsoft.net.http.headers/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll", + "lib/netstandard2.0/Microsoft.Net.Http.Headers.xml", + "microsoft.net.http.headers.2.2.0.nupkg.sha512", + "microsoft.net.http.headers.nuspec" + ] + }, + "Microsoft.NET.Test.Sdk/17.6.0": { + "sha512": "tHyg4C6c89QvLv6Utz3xKlba4EeoyJyIz59Q1NrjRENV7gfGnSE6I+sYPIbVOzQttoo2zpHDgOK/p6Hw2OlD7A==", + "type": "package", + "path": "microsoft.net.test.sdk/17.6.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE_NET.txt", + "build/net462/Microsoft.NET.Test.Sdk.props", + "build/net462/Microsoft.NET.Test.Sdk.targets", + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.Program.cs", + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.Program.fs", + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.Program.vb", + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.props", + "build/netcoreapp3.1/Microsoft.NET.Test.Sdk.targets", + "buildMultiTargeting/Microsoft.NET.Test.Sdk.props", + "lib/net462/_._", + "lib/netcoreapp3.1/_._", + "microsoft.net.test.sdk.17.6.0.nupkg.sha512", + "microsoft.net.test.sdk.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/2.0.0": { + "sha512": "VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==", + "type": "package", + "path": "microsoft.netcore.platforms/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.2.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.TestPlatform.ObjectModel/17.6.0": { + "sha512": "AA/rrf5zwC5/OBLEOajkhjbVTM3SvxRXy8kcQ8e4mJKojbyZvqqhpfNg362N9vXU94DLg9NUTFOAnoYVT0pTJw==", + "type": "package", + "path": "microsoft.testplatform.objectmodel/17.6.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE_NET.txt", + "lib/net462/Microsoft.TestPlatform.CoreUtilities.dll", + "lib/net462/Microsoft.TestPlatform.PlatformAbstractions.dll", + "lib/net462/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll", + "lib/net462/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/de/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/es/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/it/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/net462/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/net462/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll", + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll", + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll", + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/Microsoft.TestPlatform.CoreUtilities.dll", + "lib/netstandard2.0/Microsoft.TestPlatform.PlatformAbstractions.dll", + "lib/netstandard2.0/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll", + "lib/netstandard2.0/cs/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/cs/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/de/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/de/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/es/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/es/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/fr/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/fr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/it/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/it/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/ja/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/ja/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/ko/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/ko/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/pl/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/pl/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/pt-BR/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/pt-BR/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/ru/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/ru/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/tr/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/tr/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/zh-Hans/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/zh-Hans/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "lib/netstandard2.0/zh-Hant/Microsoft.TestPlatform.CoreUtilities.resources.dll", + "lib/netstandard2.0/zh-Hant/Microsoft.VisualStudio.TestPlatform.ObjectModel.resources.dll", + "microsoft.testplatform.objectmodel.17.6.0.nupkg.sha512", + "microsoft.testplatform.objectmodel.nuspec" + ] + }, + "Microsoft.TestPlatform.TestHost/17.6.0": { + "sha512": "7YdgUcIeCPVKLC7n7LNKDiEHWc7z3brkkYPdUbDnFsvf6WvY9UfzS0VSUJ8P2NgN0CDSD223GCJFSjSBLZRqOQ==", + "type": "package", + "path": "microsoft.testplatform.testhost/17.6.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE_NET.txt", + "ThirdPartyNotices.txt", + "build/netcoreapp3.1/Microsoft.TestPlatform.TestHost.props", + "build/netcoreapp3.1/x64/testhost.dll", + "build/netcoreapp3.1/x64/testhost.exe", + "build/netcoreapp3.1/x86/testhost.x86.dll", + "build/netcoreapp3.1/x86/testhost.x86.exe", + "lib/net462/_._", + "lib/netcoreapp3.1/Microsoft.TestPlatform.CommunicationUtilities.dll", + "lib/netcoreapp3.1/Microsoft.TestPlatform.CoreUtilities.dll", + "lib/netcoreapp3.1/Microsoft.TestPlatform.CrossPlatEngine.dll", + "lib/netcoreapp3.1/Microsoft.TestPlatform.PlatformAbstractions.dll", + "lib/netcoreapp3.1/Microsoft.TestPlatform.Utilities.dll", + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.Common.dll", + "lib/netcoreapp3.1/Microsoft.VisualStudio.TestPlatform.ObjectModel.dll", + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/cs/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/cs/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/de/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/de/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/es/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/es/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/fr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/fr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/it/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/it/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/ja/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/ja/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/ko/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/ko/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/pl/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/pl/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/pt-BR/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/pt-BR/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/ru/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/ru/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/testhost.deps.json", + "lib/netcoreapp3.1/testhost.dll", + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/tr/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/tr/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/x64/msdia140.dll", + "lib/netcoreapp3.1/x86/msdia140.dll", + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/zh-Hans/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/zh-Hans/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CommunicationUtilities.resources.dll", + "lib/netcoreapp3.1/zh-Hant/Microsoft.TestPlatform.CrossPlatEngine.resources.dll", + "lib/netcoreapp3.1/zh-Hant/Microsoft.VisualStudio.TestPlatform.Common.resources.dll", + "microsoft.testplatform.testhost.17.6.0.nupkg.sha512", + "microsoft.testplatform.testhost.nuspec" + ] + }, + "Microsoft.Win32.Registry/4.5.0": { + "sha512": "+FWlwd//+Tt56316p00hVePBCouXyEzT86Jb3+AuRotTND0IYn0OO3obs1gnQEs/txEnt+rF2JBGLItTG+Be6A==", + "type": "package", + "path": "microsoft.win32.registry/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "microsoft.win32.registry.4.5.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/unix/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Moq/4.18.4": { + "sha512": "IOo+W51+7Afnb0noltJrKxPBSfsgMzTKCw+Re5AMx8l/vBbAbMDOynLik4+lBYIWDJSO0uV7Zdqt7cNb6RZZ+A==", + "type": "package", + "path": "moq/4.18.4", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/Moq.dll", + "lib/net462/Moq.xml", + "lib/net6.0/Moq.dll", + "lib/net6.0/Moq.xml", + "lib/netstandard2.0/Moq.dll", + "lib/netstandard2.0/Moq.xml", + "lib/netstandard2.1/Moq.dll", + "lib/netstandard2.1/Moq.xml", + "moq.4.18.4.nupkg.sha512", + "moq.nuspec", + "moq.png" + ] + }, + "NETStandard.Library/2.0.0": { + "sha512": "7jnbRU+L08FXKMxqUflxEXtVymWvNOrS8yHgu9s6EM8Anr6T/wIX4nZ08j/u3Asz+tCufp3YVwFSEvFTPYmBPA==", + "type": "package", + "path": "netstandard.library/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "build/NETStandard.Library.targets", + "build/netstandard2.0/NETStandard.Library.targets", + "build/netstandard2.0/ref/Microsoft.Win32.Primitives.dll", + "build/netstandard2.0/ref/System.AppContext.dll", + "build/netstandard2.0/ref/System.Collections.Concurrent.dll", + "build/netstandard2.0/ref/System.Collections.NonGeneric.dll", + "build/netstandard2.0/ref/System.Collections.Specialized.dll", + "build/netstandard2.0/ref/System.Collections.dll", + "build/netstandard2.0/ref/System.ComponentModel.Composition.dll", + "build/netstandard2.0/ref/System.ComponentModel.EventBasedAsync.dll", + "build/netstandard2.0/ref/System.ComponentModel.Primitives.dll", + "build/netstandard2.0/ref/System.ComponentModel.TypeConverter.dll", + "build/netstandard2.0/ref/System.ComponentModel.dll", + "build/netstandard2.0/ref/System.Console.dll", + "build/netstandard2.0/ref/System.Core.dll", + "build/netstandard2.0/ref/System.Data.Common.dll", + "build/netstandard2.0/ref/System.Data.dll", + "build/netstandard2.0/ref/System.Diagnostics.Contracts.dll", + "build/netstandard2.0/ref/System.Diagnostics.Debug.dll", + "build/netstandard2.0/ref/System.Diagnostics.FileVersionInfo.dll", + "build/netstandard2.0/ref/System.Diagnostics.Process.dll", + "build/netstandard2.0/ref/System.Diagnostics.StackTrace.dll", + "build/netstandard2.0/ref/System.Diagnostics.TextWriterTraceListener.dll", + "build/netstandard2.0/ref/System.Diagnostics.Tools.dll", + "build/netstandard2.0/ref/System.Diagnostics.TraceSource.dll", + "build/netstandard2.0/ref/System.Diagnostics.Tracing.dll", + "build/netstandard2.0/ref/System.Drawing.Primitives.dll", + "build/netstandard2.0/ref/System.Drawing.dll", + "build/netstandard2.0/ref/System.Dynamic.Runtime.dll", + "build/netstandard2.0/ref/System.Globalization.Calendars.dll", + "build/netstandard2.0/ref/System.Globalization.Extensions.dll", + "build/netstandard2.0/ref/System.Globalization.dll", + "build/netstandard2.0/ref/System.IO.Compression.FileSystem.dll", + "build/netstandard2.0/ref/System.IO.Compression.ZipFile.dll", + "build/netstandard2.0/ref/System.IO.Compression.dll", + "build/netstandard2.0/ref/System.IO.FileSystem.DriveInfo.dll", + "build/netstandard2.0/ref/System.IO.FileSystem.Primitives.dll", + "build/netstandard2.0/ref/System.IO.FileSystem.Watcher.dll", + "build/netstandard2.0/ref/System.IO.FileSystem.dll", + "build/netstandard2.0/ref/System.IO.IsolatedStorage.dll", + "build/netstandard2.0/ref/System.IO.MemoryMappedFiles.dll", + "build/netstandard2.0/ref/System.IO.Pipes.dll", + "build/netstandard2.0/ref/System.IO.UnmanagedMemoryStream.dll", + "build/netstandard2.0/ref/System.IO.dll", + "build/netstandard2.0/ref/System.Linq.Expressions.dll", + "build/netstandard2.0/ref/System.Linq.Parallel.dll", + "build/netstandard2.0/ref/System.Linq.Queryable.dll", + "build/netstandard2.0/ref/System.Linq.dll", + "build/netstandard2.0/ref/System.Net.Http.dll", + "build/netstandard2.0/ref/System.Net.NameResolution.dll", + "build/netstandard2.0/ref/System.Net.NetworkInformation.dll", + "build/netstandard2.0/ref/System.Net.Ping.dll", + "build/netstandard2.0/ref/System.Net.Primitives.dll", + "build/netstandard2.0/ref/System.Net.Requests.dll", + "build/netstandard2.0/ref/System.Net.Security.dll", + "build/netstandard2.0/ref/System.Net.Sockets.dll", + "build/netstandard2.0/ref/System.Net.WebHeaderCollection.dll", + "build/netstandard2.0/ref/System.Net.WebSockets.Client.dll", + "build/netstandard2.0/ref/System.Net.WebSockets.dll", + "build/netstandard2.0/ref/System.Net.dll", + "build/netstandard2.0/ref/System.Numerics.dll", + "build/netstandard2.0/ref/System.ObjectModel.dll", + "build/netstandard2.0/ref/System.Reflection.Extensions.dll", + "build/netstandard2.0/ref/System.Reflection.Primitives.dll", + "build/netstandard2.0/ref/System.Reflection.dll", + "build/netstandard2.0/ref/System.Resources.Reader.dll", + "build/netstandard2.0/ref/System.Resources.ResourceManager.dll", + "build/netstandard2.0/ref/System.Resources.Writer.dll", + "build/netstandard2.0/ref/System.Runtime.CompilerServices.VisualC.dll", + "build/netstandard2.0/ref/System.Runtime.Extensions.dll", + "build/netstandard2.0/ref/System.Runtime.Handles.dll", + "build/netstandard2.0/ref/System.Runtime.InteropServices.RuntimeInformation.dll", + "build/netstandard2.0/ref/System.Runtime.InteropServices.dll", + "build/netstandard2.0/ref/System.Runtime.Numerics.dll", + "build/netstandard2.0/ref/System.Runtime.Serialization.Formatters.dll", + "build/netstandard2.0/ref/System.Runtime.Serialization.Json.dll", + "build/netstandard2.0/ref/System.Runtime.Serialization.Primitives.dll", + "build/netstandard2.0/ref/System.Runtime.Serialization.Xml.dll", + "build/netstandard2.0/ref/System.Runtime.Serialization.dll", + "build/netstandard2.0/ref/System.Runtime.dll", + "build/netstandard2.0/ref/System.Security.Claims.dll", + "build/netstandard2.0/ref/System.Security.Cryptography.Algorithms.dll", + "build/netstandard2.0/ref/System.Security.Cryptography.Csp.dll", + "build/netstandard2.0/ref/System.Security.Cryptography.Encoding.dll", + "build/netstandard2.0/ref/System.Security.Cryptography.Primitives.dll", + "build/netstandard2.0/ref/System.Security.Cryptography.X509Certificates.dll", + "build/netstandard2.0/ref/System.Security.Principal.dll", + "build/netstandard2.0/ref/System.Security.SecureString.dll", + "build/netstandard2.0/ref/System.ServiceModel.Web.dll", + "build/netstandard2.0/ref/System.Text.Encoding.Extensions.dll", + "build/netstandard2.0/ref/System.Text.Encoding.dll", + "build/netstandard2.0/ref/System.Text.RegularExpressions.dll", + "build/netstandard2.0/ref/System.Threading.Overlapped.dll", + "build/netstandard2.0/ref/System.Threading.Tasks.Parallel.dll", + "build/netstandard2.0/ref/System.Threading.Tasks.dll", + "build/netstandard2.0/ref/System.Threading.Thread.dll", + "build/netstandard2.0/ref/System.Threading.ThreadPool.dll", + "build/netstandard2.0/ref/System.Threading.Timer.dll", + "build/netstandard2.0/ref/System.Threading.dll", + "build/netstandard2.0/ref/System.Transactions.dll", + "build/netstandard2.0/ref/System.ValueTuple.dll", + "build/netstandard2.0/ref/System.Web.dll", + "build/netstandard2.0/ref/System.Windows.dll", + "build/netstandard2.0/ref/System.Xml.Linq.dll", + "build/netstandard2.0/ref/System.Xml.ReaderWriter.dll", + "build/netstandard2.0/ref/System.Xml.Serialization.dll", + "build/netstandard2.0/ref/System.Xml.XDocument.dll", + "build/netstandard2.0/ref/System.Xml.XPath.XDocument.dll", + "build/netstandard2.0/ref/System.Xml.XPath.dll", + "build/netstandard2.0/ref/System.Xml.XmlDocument.dll", + "build/netstandard2.0/ref/System.Xml.XmlSerializer.dll", + "build/netstandard2.0/ref/System.Xml.dll", + "build/netstandard2.0/ref/System.dll", + "build/netstandard2.0/ref/mscorlib.dll", + "build/netstandard2.0/ref/netstandard.dll", + "build/netstandard2.0/ref/netstandard.xml", + "lib/netstandard1.0/_._", + "netstandard.library.2.0.0.nupkg.sha512", + "netstandard.library.nuspec" + ] + }, + "Newtonsoft.Json/13.0.2": { + "sha512": "R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==", + "type": "package", + "path": "newtonsoft.json/13.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.2.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "NuGet.Frameworks/5.11.0": { + "sha512": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==", + "type": "package", + "path": "nuget.frameworks/5.11.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icon.png", + "lib/net40/NuGet.Frameworks.dll", + "lib/net40/NuGet.Frameworks.xml", + "lib/net472/NuGet.Frameworks.dll", + "lib/net472/NuGet.Frameworks.xml", + "lib/netstandard2.0/NuGet.Frameworks.dll", + "lib/netstandard2.0/NuGet.Frameworks.xml", + "nuget.frameworks.5.11.0.nupkg.sha512", + "nuget.frameworks.nuspec" + ] + }, + "NUnit/3.13.3": { + "sha512": "KNPDpls6EfHwC3+nnA67fh5wpxeLb3VLFAfLxrug6JMYDLHH6InaQIWR7Sc3y75d/9IKzMksH/gi08W7XWbmnQ==", + "type": "package", + "path": "nunit/3.13.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CHANGES.md", + "LICENSE.txt", + "NOTICES.txt", + "build/NUnit.props", + "icon.png", + "lib/net35/nunit.framework.dll", + "lib/net35/nunit.framework.xml", + "lib/net40/nunit.framework.dll", + "lib/net40/nunit.framework.xml", + "lib/net45/nunit.framework.dll", + "lib/net45/nunit.framework.xml", + "lib/netstandard2.0/nunit.framework.dll", + "lib/netstandard2.0/nunit.framework.xml", + "nunit.3.13.3.nupkg.sha512", + "nunit.nuspec" + ] + }, + "NUnit3TestAdapter/4.4.2": { + "sha512": "vA/iHYcR+LYw+pRWQugckC/zW2fXHaqMr2uA82NOBt8v4YK4wMJrQ7QC8XLc7PjetEZ96cPbBTWsDDtmQiRZTA==", + "type": "package", + "path": "nunit3testadapter/4.4.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/net462/NUnit3.TestAdapter.dll", + "build/net462/NUnit3.TestAdapter.pdb", + "build/net462/NUnit3TestAdapter.props", + "build/net462/nunit.engine.api.dll", + "build/net462/nunit.engine.core.dll", + "build/net462/nunit.engine.dll", + "build/net462/testcentric.engine.metadata.dll", + "build/netcoreapp3.1/NUnit3.TestAdapter.dll", + "build/netcoreapp3.1/NUnit3.TestAdapter.pdb", + "build/netcoreapp3.1/NUnit3TestAdapter.props", + "build/netcoreapp3.1/nunit.engine.api.dll", + "build/netcoreapp3.1/nunit.engine.core.dll", + "build/netcoreapp3.1/nunit.engine.dll", + "build/netcoreapp3.1/testcentric.engine.metadata.dll", + "docs/README.md", + "nunit3testadapter.4.4.2.nupkg.sha512", + "nunit3testadapter.nuspec", + "nunit_256.png" + ] + }, + "System.Buffers/4.5.0": { + "sha512": "pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A==", + "type": "package", + "path": "system.buffers/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.0.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.ComponentModel.Annotations/4.5.0": { + "sha512": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==", + "type": "package", + "path": "system.componentmodel.annotations/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net461/System.ComponentModel.Annotations.dll", + "lib/netcore50/System.ComponentModel.Annotations.dll", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.4/System.ComponentModel.Annotations.dll", + "lib/netstandard2.0/System.ComponentModel.Annotations.dll", + "lib/portable-net45+win8/_._", + "lib/uap10.0.16299/_._", + "lib/win8/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net461/System.ComponentModel.Annotations.dll", + "ref/net461/System.ComponentModel.Annotations.xml", + "ref/netcore50/System.ComponentModel.Annotations.dll", + "ref/netcore50/System.ComponentModel.Annotations.xml", + "ref/netcore50/de/System.ComponentModel.Annotations.xml", + "ref/netcore50/es/System.ComponentModel.Annotations.xml", + "ref/netcore50/fr/System.ComponentModel.Annotations.xml", + "ref/netcore50/it/System.ComponentModel.Annotations.xml", + "ref/netcore50/ja/System.ComponentModel.Annotations.xml", + "ref/netcore50/ko/System.ComponentModel.Annotations.xml", + "ref/netcore50/ru/System.ComponentModel.Annotations.xml", + "ref/netcore50/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netcore50/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.ComponentModel.Annotations.dll", + "ref/netstandard1.1/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/System.ComponentModel.Annotations.dll", + "ref/netstandard1.3/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/System.ComponentModel.Annotations.dll", + "ref/netstandard1.4/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard2.0/System.ComponentModel.Annotations.dll", + "ref/netstandard2.0/System.ComponentModel.Annotations.xml", + "ref/portable-net45+win8/_._", + "ref/uap10.0.16299/_._", + "ref/win8/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.componentmodel.annotations.4.5.0.nupkg.sha512", + "system.componentmodel.annotations.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Diagnostics.EventLog/6.0.0": { + "sha512": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==", + "type": "package", + "path": "system.diagnostics.eventlog/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Diagnostics.EventLog.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/System.Diagnostics.EventLog.dll", + "lib/net461/System.Diagnostics.EventLog.xml", + "lib/net6.0/System.Diagnostics.EventLog.dll", + "lib/net6.0/System.Diagnostics.EventLog.xml", + "lib/netcoreapp3.1/System.Diagnostics.EventLog.dll", + "lib/netcoreapp3.1/System.Diagnostics.EventLog.xml", + "lib/netstandard2.0/System.Diagnostics.EventLog.dll", + "lib/netstandard2.0/System.Diagnostics.EventLog.xml", + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll", + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll", + "runtimes/win/lib/net6.0/System.Diagnostics.EventLog.xml", + "runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.Messages.dll", + "runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.dll", + "runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.xml", + "system.diagnostics.eventlog.6.0.0.nupkg.sha512", + "system.diagnostics.eventlog.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Linq.Dynamic.Core/1.2.25": { + "sha512": "qpkqDHLNxGR1qBNrdnnPfJFfsKSWy3nUELC/BWxP8vwSaf8vVwecZzXOV4B52yOGit94g0pLWJEe30a4L1tE7g==", + "type": "package", + "path": "system.linq.dynamic.core/1.2.25", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net35/System.Linq.Dynamic.Core.dll", + "lib/net35/System.Linq.Dynamic.Core.pdb", + "lib/net35/System.Linq.Dynamic.Core.xml", + "lib/net40/System.Linq.Dynamic.Core.dll", + "lib/net40/System.Linq.Dynamic.Core.pdb", + "lib/net40/System.Linq.Dynamic.Core.xml", + "lib/net45/System.Linq.Dynamic.Core.dll", + "lib/net45/System.Linq.Dynamic.Core.pdb", + "lib/net45/System.Linq.Dynamic.Core.xml", + "lib/net452/System.Linq.Dynamic.Core.dll", + "lib/net452/System.Linq.Dynamic.Core.pdb", + "lib/net452/System.Linq.Dynamic.Core.xml", + "lib/net46/System.Linq.Dynamic.Core.dll", + "lib/net46/System.Linq.Dynamic.Core.pdb", + "lib/net46/System.Linq.Dynamic.Core.xml", + "lib/net5.0/System.Linq.Dynamic.Core.dll", + "lib/net5.0/System.Linq.Dynamic.Core.pdb", + "lib/net5.0/System.Linq.Dynamic.Core.xml", + "lib/net6.0/System.Linq.Dynamic.Core.dll", + "lib/net6.0/System.Linq.Dynamic.Core.pdb", + "lib/net6.0/System.Linq.Dynamic.Core.xml", + "lib/net7.0/System.Linq.Dynamic.Core.dll", + "lib/net7.0/System.Linq.Dynamic.Core.pdb", + "lib/net7.0/System.Linq.Dynamic.Core.xml", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.dll", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.pdb", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.xml", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.dll", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.pdb", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.xml", + "lib/netstandard1.3/System.Linq.Dynamic.Core.dll", + "lib/netstandard1.3/System.Linq.Dynamic.Core.pdb", + "lib/netstandard1.3/System.Linq.Dynamic.Core.xml", + "lib/netstandard2.0/System.Linq.Dynamic.Core.dll", + "lib/netstandard2.0/System.Linq.Dynamic.Core.pdb", + "lib/netstandard2.0/System.Linq.Dynamic.Core.xml", + "lib/netstandard2.1/System.Linq.Dynamic.Core.dll", + "lib/netstandard2.1/System.Linq.Dynamic.Core.pdb", + "lib/netstandard2.1/System.Linq.Dynamic.Core.xml", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.dll", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.pdb", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.pri", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.xml", + "logo.png", + "system.linq.dynamic.core.1.2.25.nupkg.sha512", + "system.linq.dynamic.core.nuspec" + ] + }, + "System.Reflection.Metadata/1.6.0": { + "sha512": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==", + "type": "package", + "path": "system.reflection.metadata/1.6.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.1/System.Reflection.Metadata.dll", + "lib/netstandard1.1/System.Reflection.Metadata.xml", + "lib/netstandard2.0/System.Reflection.Metadata.dll", + "lib/netstandard2.0/System.Reflection.Metadata.xml", + "lib/portable-net45+win8/System.Reflection.Metadata.dll", + "lib/portable-net45+win8/System.Reflection.Metadata.xml", + "system.reflection.metadata.1.6.0.nupkg.sha512", + "system.reflection.metadata.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "sha512": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net461/System.Runtime.CompilerServices.Unsafe.xml", + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Security.AccessControl/4.5.0": { + "sha512": "vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==", + "type": "package", + "path": "system.security.accesscontrol/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.4.5.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Cryptography.Cng/4.5.0": { + "sha512": "WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==", + "type": "package", + "path": "system.security.cryptography.cng/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Cng.dll", + "lib/net461/System.Security.Cryptography.Cng.dll", + "lib/net462/System.Security.Cryptography.Cng.dll", + "lib/net47/System.Security.Cryptography.Cng.dll", + "lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll", + "lib/netstandard1.3/System.Security.Cryptography.Cng.dll", + "lib/netstandard1.4/System.Security.Cryptography.Cng.dll", + "lib/netstandard1.6/System.Security.Cryptography.Cng.dll", + "lib/netstandard2.0/System.Security.Cryptography.Cng.dll", + "lib/uap10.0.16299/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Cng.dll", + "ref/net461/System.Security.Cryptography.Cng.dll", + "ref/net461/System.Security.Cryptography.Cng.xml", + "ref/net462/System.Security.Cryptography.Cng.dll", + "ref/net462/System.Security.Cryptography.Cng.xml", + "ref/net47/System.Security.Cryptography.Cng.dll", + "ref/net47/System.Security.Cryptography.Cng.xml", + "ref/netcoreapp2.0/System.Security.Cryptography.Cng.dll", + "ref/netcoreapp2.0/System.Security.Cryptography.Cng.xml", + "ref/netcoreapp2.1/System.Security.Cryptography.Cng.dll", + "ref/netcoreapp2.1/System.Security.Cryptography.Cng.xml", + "ref/netstandard1.3/System.Security.Cryptography.Cng.dll", + "ref/netstandard1.4/System.Security.Cryptography.Cng.dll", + "ref/netstandard1.6/System.Security.Cryptography.Cng.dll", + "ref/netstandard2.0/System.Security.Cryptography.Cng.dll", + "ref/netstandard2.0/System.Security.Cryptography.Cng.xml", + "ref/uap10.0.16299/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "runtimes/win/lib/net46/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/net461/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/net462/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/net47/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netstandard1.4/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netstandard1.6/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.cryptography.cng.4.5.0.nupkg.sha512", + "system.security.cryptography.cng.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Cryptography.Pkcs/4.5.0": { + "sha512": "TGQX51gxpY3K3I6LJlE2LAftVlIMqJf0cBGhz68Y89jjk3LJCB6SrwiD+YN1fkqemBvWGs+GjyMJukl6d6goyQ==", + "type": "package", + "path": "system.security.cryptography.pkcs/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Cryptography.Pkcs.dll", + "lib/net461/System.Security.Cryptography.Pkcs.dll", + "lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll", + "lib/netstandard1.3/System.Security.Cryptography.Pkcs.dll", + "lib/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "ref/net46/System.Security.Cryptography.Pkcs.dll", + "ref/net461/System.Security.Cryptography.Pkcs.dll", + "ref/net461/System.Security.Cryptography.Pkcs.xml", + "ref/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll", + "ref/netcoreapp2.1/System.Security.Cryptography.Pkcs.xml", + "ref/netstandard1.3/System.Security.Cryptography.Pkcs.dll", + "ref/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "ref/netstandard2.0/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/net46/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/net461/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netstandard1.3/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "system.security.cryptography.pkcs.4.5.0.nupkg.sha512", + "system.security.cryptography.pkcs.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Cryptography.Xml/4.5.0": { + "sha512": "i2Jn6rGXR63J0zIklImGRkDIJL4b1NfPSEbIVHBlqoIb12lfXIigCbDRpDmIEzwSo/v1U5y/rYJdzZYSyCWxvg==", + "type": "package", + "path": "system.security.cryptography.xml/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Security.Cryptography.Xml.dll", + "lib/netstandard2.0/System.Security.Cryptography.Xml.dll", + "ref/net461/System.Security.Cryptography.Xml.dll", + "ref/net461/System.Security.Cryptography.Xml.xml", + "ref/netstandard2.0/System.Security.Cryptography.Xml.dll", + "ref/netstandard2.0/System.Security.Cryptography.Xml.xml", + "system.security.cryptography.xml.4.5.0.nupkg.sha512", + "system.security.cryptography.xml.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Permissions/4.5.0": { + "sha512": "9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==", + "type": "package", + "path": "system.security.permissions/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Security.Permissions.dll", + "lib/netstandard2.0/System.Security.Permissions.dll", + "ref/net461/System.Security.Permissions.dll", + "ref/net461/System.Security.Permissions.xml", + "ref/netstandard2.0/System.Security.Permissions.dll", + "ref/netstandard2.0/System.Security.Permissions.xml", + "system.security.permissions.4.5.0.nupkg.sha512", + "system.security.permissions.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/4.5.0": { + "sha512": "U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "type": "package", + "path": "system.security.principal.windows/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.4.5.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Text.Encodings.Web/4.5.0": { + "sha512": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==", + "type": "package", + "path": "system.text.encodings.web/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/System.Text.Encodings.Web.dll", + "lib/netstandard1.0/System.Text.Encodings.Web.xml", + "lib/netstandard2.0/System.Text.Encodings.Web.dll", + "lib/netstandard2.0/System.Text.Encodings.Web.xml", + "system.text.encodings.web.4.5.0.nupkg.sha512", + "system.text.encodings.web.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "e-Suite.Modules.ContactsManager/1.0.0": { + "type": "project", + "path": "../e-Suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.csproj", + "msbuildProject": "../e-Suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.csproj" + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "Microsoft.NET.Test.Sdk >= 17.6.0", + "NUnit >= 3.13.3", + "NUnit3TestAdapter >= 4.4.2", + "coverlet.collector >= 6.0.0", + "e-Suite.Modules.ContactsManager >= 1.0.0", + "e-suite.Database.Core >= 2023.5.23.1-beta", + "e-suite.UnitTestCore >= 2023.5.23.1-beta" + ] + }, + "packageFolders": { + "C:\\Users\\me\\.nuget\\packages\\": {}, + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj", + "projectName": "e-Suite.Modules.ContactsManager.UnitTests", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\NuGet.Config", + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "Microsoft.NET.Test.Sdk": { + "target": "Package", + "version": "[17.6.0, )" + }, + "NUnit": { + "target": "Package", + "version": "[3.13.3, )" + }, + "NUnit3TestAdapter": { + "target": "Package", + "version": "[4.4.2, )" + }, + "coverlet.collector": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[6.0.0, )" + }, + "e-suite.Database.Core": { + "target": "Package", + "version": "[2023.5.23.1-beta, )" + }, + "e-suite.UnitTestCore": { + "target": "Package", + "version": "[2023.5.23.1-beta, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/project.nuget.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/project.nuget.cache new file mode 100644 index 0000000..6198882 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager.UnitTests/obj/project.nuget.cache @@ -0,0 +1,78 @@ +{ + "version": 2, + "dgSpecHash": "6ozWll5A9tfAPoOpv6C8TVIhU/TgfOFMsP7cA1dgtFw1VBgIpJmGXsOQJCRONzT7MFWbBlaxUdPO9zuqz7GWuA==", + "success": true, + "projectFilePath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.UnitTests\\e-Suite.Modules.ContactsManager.UnitTests.csproj", + "expectedPackageFiles": [ + "C:\\Users\\me\\.nuget\\packages\\castle.core\\5.1.1\\castle.core.5.1.1.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\coverlet.collector\\6.0.0\\coverlet.collector.6.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.api.common\\2023.5.23.21-beta\\e-suite.api.common.2023.5.23.21-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.database.audit\\2023.5.23.1-beta\\e-suite.database.audit.2023.5.23.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.database.core\\2023.5.23.1-beta\\e-suite.database.core.2023.5.23.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.unittestcore\\2023.5.23.1-beta\\e-suite.unittestcore.2023.5.23.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.utilities.pagination\\2023.5.16.1-beta\\e-suite.utilities.pagination.2023.5.16.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\esuite.core\\2023.3.31.1-beta\\esuite.core.2023.3.31.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e_suite.nuget.passwordhasher\\2022.12.1.1\\e_suite.nuget.passwordhasher.2022.12.1.1.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication\\2.2.0\\microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication.abstractions\\2.2.0\\microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication.cookies\\2.2.0\\microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication.core\\2.2.0\\microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.cryptography.internal\\2.2.0\\microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.cryptography.keyderivation\\2.2.0\\microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.dataprotection\\2.2.0\\microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.dataprotection.abstractions\\2.2.0\\microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.hosting.abstractions\\2.2.0\\microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.hosting.server.abstractions\\2.2.0\\microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http\\2.2.0\\microsoft.aspnetcore.http.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http.abstractions\\2.2.0\\microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http.extensions\\2.2.0\\microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http.features\\2.2.0\\microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.identity\\2.2.0\\microsoft.aspnetcore.identity.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.webutilities\\2.2.0\\microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.codecoverage\\17.6.0\\microsoft.codecoverage.17.6.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore\\7.0.5\\microsoft.entityframeworkcore.7.0.5.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore.abstractions\\7.0.5\\microsoft.entityframeworkcore.abstractions.7.0.5.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore.analyzers\\7.0.5\\microsoft.entityframeworkcore.analyzers.7.0.5.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\7.0.0\\microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.caching.memory\\7.0.0\\microsoft.extensions.caching.memory.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.configuration\\7.0.0\\microsoft.extensions.configuration.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\7.0.0\\microsoft.extensions.configuration.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\7.0.0\\microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\7.0.0\\microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.fileproviders.abstractions\\2.2.0\\microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.hosting.abstractions\\2.2.0\\microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.identity.core\\2.2.0\\microsoft.extensions.identity.core.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.logging\\7.0.0\\microsoft.extensions.logging.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\7.0.0\\microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.objectpool\\2.2.0\\microsoft.extensions.objectpool.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.options\\7.0.0\\microsoft.extensions.options.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.primitives\\7.0.0\\microsoft.extensions.primitives.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.webencoders\\2.2.0\\microsoft.extensions.webencoders.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.net.http.headers\\2.2.0\\microsoft.net.http.headers.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.net.test.sdk\\17.6.0\\microsoft.net.test.sdk.17.6.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.netcore.platforms\\2.0.0\\microsoft.netcore.platforms.2.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.testplatform.objectmodel\\17.6.0\\microsoft.testplatform.objectmodel.17.6.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.testplatform.testhost\\17.6.0\\microsoft.testplatform.testhost.17.6.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.win32.registry\\4.5.0\\microsoft.win32.registry.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\moq\\4.18.4\\moq.4.18.4.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\netstandard.library\\2.0.0\\netstandard.library.2.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\newtonsoft.json\\13.0.2\\newtonsoft.json.13.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\nuget.frameworks\\5.11.0\\nuget.frameworks.5.11.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\nunit\\3.13.3\\nunit.3.13.3.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\nunit3testadapter\\4.4.2\\nunit3testadapter.4.4.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.buffers\\4.5.0\\system.buffers.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.componentmodel.annotations\\4.5.0\\system.componentmodel.annotations.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.diagnostics.eventlog\\6.0.0\\system.diagnostics.eventlog.6.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.linq.dynamic.core\\1.2.25\\system.linq.dynamic.core.1.2.25.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.reflection.metadata\\1.6.0\\system.reflection.metadata.1.6.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.runtime.compilerservices.unsafe\\6.0.0\\system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.accesscontrol\\4.5.0\\system.security.accesscontrol.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.cryptography.cng\\4.5.0\\system.security.cryptography.cng.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.cryptography.pkcs\\4.5.0\\system.security.cryptography.pkcs.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.cryptography.xml\\4.5.0\\system.security.cryptography.xml.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.permissions\\4.5.0\\system.security.permissions.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.principal.windows\\4.5.0\\system.security.principal.windows.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.text.encodings.web\\4.5.0\\system.text.encodings.web.4.5.0.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.deps.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.deps.json new file mode 100644 index 0000000..3232408 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.deps.json @@ -0,0 +1,954 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "e-Suite.Modules.ContactsManager/1.0.0": { + "dependencies": { + "e-suite.API.Common": "2023.5.23.18-beta", + "e-suite.Database.Core": "2023.5.17.2-beta" + }, + "runtime": { + "e-Suite.Modules.ContactsManager.dll": {} + } + }, + "e-suite.API.Common/2023.5.23.18-beta": { + "dependencies": { + "e-suite.Database.Core": "2023.5.17.2-beta", + "e-suite.Utilities.Pagination": "2023.5.16.1-beta" + }, + "runtime": { + "lib/net6.0/e-suite.API.Common.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Audit/2023.5.16.1-beta": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.5", + "Newtonsoft.Json": "13.0.2", + "System.Linq.Dynamic.Core": "1.2.25", + "eSuite.Core": "2023.2.21.1-beta" + }, + "runtime": { + "lib/net6.0/e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/2023.5.17.2-beta": { + "dependencies": { + "e-suite.Database.Audit": "2023.5.16.1-beta", + "e_suite.Nuget.PasswordHasher": "2022.12.1.1" + }, + "runtime": { + "lib/net6.0/e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.5" + }, + "runtime": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/2023.2.21.1-beta": { + "runtime": { + "lib/net6.0/eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "dependencies": { + "Microsoft.AspNetCore.Identity": "2.2.0" + }, + "runtime": { + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication.Core": "2.2.0", + "Microsoft.AspNetCore.DataProtection": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.WebEncoders": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0" + }, + "runtime": { + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0", + "Microsoft.AspNetCore.DataProtection.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Win32.Registry": "4.5.0", + "System.Security.Cryptography.Xml": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Hosting.Server.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Hosting.Abstractions": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.AspNetCore.WebUtilities": "2.2.0", + "Microsoft.Extensions.ObjectPool": "2.2.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Net.Http.Headers": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Buffers": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Authentication.Cookies": "2.2.0", + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.Identity.Core": "2.2.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "dependencies": { + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.5", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.5", + "Microsoft.Extensions.Caching.Memory": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "7.0.5.0", + "fileVersion": "7.0.523.16503" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "7.0.5.0", + "fileVersion": "7.0.523.16503" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": {}, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18315" + } + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18315" + } + } + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "dependencies": { + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.ComponentModel.Annotations": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.Extensions.Logging/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18315" + } + } + }, + "Microsoft.Extensions.Options/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0", + "System.Buffers": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll": { + "assemblyVersion": "2.2.0.0", + "fileVersion": "2.2.0.18316" + } + } + }, + "Microsoft.NETCore.Platforms/2.0.0": {}, + "Microsoft.Win32.Registry/4.5.0": { + "dependencies": { + "System.Security.AccessControl": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "Newtonsoft.Json/13.0.2": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.2.27524" + } + } + }, + "System.Buffers/4.5.0": {}, + "System.ComponentModel.Annotations/4.5.0": {}, + "System.Linq.Dynamic.Core/1.2.25": { + "runtime": { + "lib/net6.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.2.25.0", + "fileVersion": "1.2.25.0" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": {}, + "System.Security.AccessControl/4.5.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "System.Security.Cryptography.Cng/4.5.0": {}, + "System.Security.Cryptography.Pkcs/4.5.0": { + "dependencies": { + "System.Security.Cryptography.Cng": "4.5.0" + }, + "runtime": { + "lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.6.26515.6" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Security.Cryptography.Xml/4.5.0": { + "dependencies": { + "System.Security.Cryptography.Pkcs": "4.5.0", + "System.Security.Permissions": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/System.Security.Cryptography.Xml.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Security.Permissions/4.5.0": { + "dependencies": { + "System.Security.AccessControl": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/System.Security.Permissions.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Security.Principal.Windows/4.5.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + } + }, + "System.Text.Encodings.Web/4.5.0": {} + } + }, + "libraries": { + "e-Suite.Modules.ContactsManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e-suite.API.Common/2023.5.23.18-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-8h39GbWtL3ljouEHEcXsfngRACkZTA5ejzFy5r2fc2eejK4JHwkZakSdrqXZJNX8pt/BaN5XWgLUPkCwpT3iNw==", + "path": "e-suite.api.common/2023.5.23.18-beta", + "hashPath": "e-suite.api.common.2023.5.23.18-beta.nupkg.sha512" + }, + "e-suite.Database.Audit/2023.5.16.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+gSdDGHoiLA1w45KXb+REsgumVjsluPrNv5tJdj5i39U0uSvnkJssK9IMdxSh+t+b3wL33NhHiJ1jRFNUoGOAQ==", + "path": "e-suite.database.audit/2023.5.16.1-beta", + "hashPath": "e-suite.database.audit.2023.5.16.1-beta.nupkg.sha512" + }, + "e-suite.Database.Core/2023.5.17.2-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5jJ2ZPF2ddeS6sakLTESeLSRhFV3Gv8R/yBjzc2H6opkzuaXIH1YuewkM5XAEzwKyRhyBdAeyjIM/l8QalrPFQ==", + "path": "e-suite.database.core/2023.5.17.2-beta", + "hashPath": "e-suite.database.core.2023.5.17.2-beta.nupkg.sha512" + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0k9sjGp9YZpRUQaiyBkQpmslJTMOJ7ZR/f8Latc02Amcw953pB//CN+/XGGOO09FuxA3cWIsDQ9WsSEVU9iwxg==", + "path": "e-suite.utilities.pagination/2023.5.16.1-beta", + "hashPath": "e-suite.utilities.pagination.2023.5.16.1-beta.nupkg.sha512" + }, + "eSuite.Core/2023.2.21.1-beta": { + "type": "package", + "serviceable": true, + "sha512": "sha512-BtyGim1HKP1xDUDS8WEzlozO/kXP7Mk1P02i/CXAtjFtawXVnnNq8lcVTZCU1nK7JzfpU0j2tZZVW5RYNkW5/Q==", + "path": "esuite.core/2023.2.21.1-beta", + "hashPath": "esuite.core.2023.2.21.1-beta.nupkg.sha512" + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-oKt0q1UISYgWj9v72yIEhvYkcdHiw8SNIQUkE+DZJ1FuVkCqPknzMiFIZY3FKGZOQf0XY1pgccazZPyl+06VWQ==", + "path": "e_suite.nuget.passwordhasher/2022.12.1.1", + "hashPath": "e_suite.nuget.passwordhasher.2022.12.1.1.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-b0R9X7L6zMqNsssKDvhYHuNi5x0s4DyHTeXybIAyGaitKiW1Q5aAGKdV2codHPiePv9yHfC9hAMyScXQ/xXhPw==", + "path": "microsoft.aspnetcore.authentication/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VloMLDJMf3n/9ic5lCBOa42IBYJgyB1JhzLsL68Zqg+2bEPWfGBj/xCJy/LrKTArN0coOcZp3wyVTZlx0y9pHQ==", + "path": "microsoft.aspnetcore.authentication.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Iar9VFlBHkZGdSG9ZUTmn6Q8Qg+6CtW5G/TyJI2F8B432TOH+nZlkU7O0W0byow6xsxqOYeTviSHz4cCJ3amfQ==", + "path": "microsoft.aspnetcore.authentication.cookies/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XlVJzJ5wPOYW+Y0J6Q/LVTEyfS4ssLXmt60T0SPP+D8abVhBTl+cgw2gDHlyKYIkcJg7btMVh383NDkMVqD/fg==", + "path": "microsoft.aspnetcore.authentication.core/2.2.0", + "hashPath": "microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-GXmMD8/vuTLPLvKzKEPz/4vapC5e0cwx1tUVd83ePRyWF9CCrn/pg4/1I+tGkQqFLPvi3nlI2QtPtC6MQN8Nww==", + "path": "microsoft.aspnetcore.cryptography.internal/2.2.0", + "hashPath": "microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NCY0PH3nrFYbhqiq72rwWsUXlV4OAE0MOukvGvIBOTnEPMC1yVL42k1DXLnaIu+c0yfMAxIIG9Iuaykp9BQQQw==", + "path": "microsoft.aspnetcore.cryptography.keyderivation/2.2.0", + "hashPath": "microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-G6dvu5Nd2vjpYbzazZ//qBFbSEf2wmBUbyAR7E4AwO3gWjhoJD5YxpThcGJb7oE3VUcW65SVMXT+cPCiiBg8Sg==", + "path": "microsoft.aspnetcore.dataprotection/2.2.0", + "hashPath": "microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-seANFXmp8mb5Y12m1ShiElJ3ZdOT3mBN3wA1GPhHJIvZ/BxOCPyqEOR+810OWsxEZwA5r5fDRNpG/CqiJmQnJg==", + "path": "microsoft.aspnetcore.dataprotection.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ubycklv+ZY7Kutdwuy1W4upWcZ6VFR8WUXU7l7B2+mvbDBBPAcfpi+E+Y5GFe+Q157YfA3C49D2GCjAZc7Mobw==", + "path": "microsoft.aspnetcore.hosting.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1PMijw8RMtuQF60SsD/JlKtVfvh4NORAhF4wjysdABhlhTrYmtgssqyncR0Stq5vqtjplZcj6kbT4LRTglt9IQ==", + "path": "microsoft.aspnetcore.hosting.server.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-YogBSMotWPAS/X5967pZ+yyWPQkThxhmzAwyCHCSSldzYBkW5W5d6oPfBaPqQOnSHYTpSOSOkpZoAce0vwb6+A==", + "path": "microsoft.aspnetcore.http/2.2.0", + "hashPath": "microsoft.aspnetcore.http.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==", + "path": "microsoft.aspnetcore.http.abstractions/2.2.0", + "hashPath": "microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2DgZ9rWrJtuR7RYiew01nGRzuQBDaGHGmK56Rk54vsLLsCdzuFUPqbDTJCS1qJQWTbmbIQ9wGIOjpxA1t0l7/w==", + "path": "microsoft.aspnetcore.http.extensions/2.2.0", + "hashPath": "microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==", + "path": "microsoft.aspnetcore.http.features/2.2.0", + "hashPath": "microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-F16BKeS96wKhyIyhaFR7m8kRIwIvPUW9Dx7IlGWmu2IIwnUDCdo+2z7IrWKA8r77pZQ1UE9kYcBPg5456YdAIA==", + "path": "microsoft.aspnetcore.identity/2.2.0", + "hashPath": "microsoft.aspnetcore.identity.2.2.0.nupkg.sha512" + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9ErxAAKaDzxXASB/b5uLEkLgUWv1QbeVxyJYEHQwMaxXOeFFVkQxiq8RyfVcifLU7NR0QY0p3acqx4ZpYfhHDg==", + "path": "microsoft.aspnetcore.webutilities/2.2.0", + "hashPath": "microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RXbRLHHWP2Z3pq8qcL5nQ6LPeoOyp8hasM5bd0Te8PiQi3RjWQR4tcbdY5XMqQ+oTO9wA8/RLhZRn/hnxlTDnQ==", + "path": "microsoft.entityframeworkcore/7.0.5", + "hashPath": "microsoft.entityframeworkcore.7.0.5.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-iwQso+hFRsEWjhH2WsEQj1D2QE5BlEXiXEt6A3SlYTPRPdZsyTNDeDDEdtxL+H/UJPQgQYY+9SMMRcEiXBmCAA==", + "path": "microsoft.entityframeworkcore.abstractions/7.0.5", + "hashPath": "microsoft.entityframeworkcore.abstractions.7.0.5.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yMLM/aK1MikVqpjxd7PJ1Pjgztd3VAd26ZHxyjxG3RPeM9cHjvS5tCg9kAAayR6eHmBg0ffZsHdT28WfA5tTlA==", + "path": "microsoft.entityframeworkcore.analyzers/7.0.5", + "hashPath": "microsoft.entityframeworkcore.analyzers.7.0.5.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IeimUd0TNbhB4ded3AbgBLQv2SnsiVugDyGV1MvspQFVlA07nDC7Zul7kcwH5jWN3JiTcp/ySE83AIJo8yfKjg==", + "path": "microsoft.extensions.caching.abstractions/7.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-xpidBs2KCE2gw1JrD0quHE72kvCaI3xFql5/Peb2GRtUuZX+dYPoK/NTdVMiM67Svym0M0Df9A3xyU0FbMQhHw==", + "path": "microsoft.extensions.caching.memory/7.0.0", + "hashPath": "microsoft.extensions.caching.memory.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", + "path": "microsoft.extensions.configuration.abstractions/2.2.0", + "hashPath": "microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-EcnaSsPTqx2MGnHrmWOD0ugbuuqVT8iICqSqPzi45V5/MA1LjUNb0kwgcxBGqizV1R+WeBK7/Gw25Jzkyk9bIw==", + "path": "microsoft.extensions.fileproviders.abstractions/2.2.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+k4AEn68HOJat5gj1TWa6X28WlirNQO9sPIIeQbia+91n03esEtMSSoekSTpMjUzjqtJWQN3McVx0GvSPFHF/Q==", + "path": "microsoft.extensions.hosting.abstractions/2.2.0", + "hashPath": "microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/C+Valwg8IeUwDIunusittHivA9iyf82Jr1yeUFWO2zH2mDMMeYgjRyDLZqfL/7Vq94PEQsgv1XAaDfAX8msMw==", + "path": "microsoft.extensions.identity.core/2.2.0", + "hashPath": "microsoft.extensions.identity.core.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "path": "microsoft.extensions.logging/7.0.0", + "hashPath": "microsoft.extensions.logging.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-gA8H7uQOnM5gb+L0uTNjViHYr+hRDqCdfugheGo/MxQnuHzmhhzCBTIPm19qL1z1Xe0NEMabfcOBGv9QghlZ8g==", + "path": "microsoft.extensions.objectpool/2.2.0", + "hashPath": "microsoft.extensions.objectpool.2.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "path": "microsoft.extensions.options/7.0.0", + "hashPath": "microsoft.extensions.options.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==", + "path": "microsoft.extensions.primitives/7.0.0", + "hashPath": "microsoft.extensions.primitives.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-V8XcqYcpcdBAxUhLeyYcuKmxu4CtNQA9IphTnARpQGhkop4A93v2XgM3AtaVVJo3H2cDWxWM6aeO8HxkifREqw==", + "path": "microsoft.extensions.webencoders/2.2.0", + "hashPath": "microsoft.extensions.webencoders.2.2.0.nupkg.sha512" + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-iZNkjYqlo8sIOI0bQfpsSoMTmB/kyvmV2h225ihyZT33aTp48ZpF6qYnXxzSXmHt8DpBAwBTX+1s1UFLbYfZKg==", + "path": "microsoft.net.http.headers/2.2.0", + "hashPath": "microsoft.net.http.headers.2.2.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==", + "path": "microsoft.netcore.platforms/2.0.0", + "hashPath": "microsoft.netcore.platforms.2.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+FWlwd//+Tt56316p00hVePBCouXyEzT86Jb3+AuRotTND0IYn0OO3obs1gnQEs/txEnt+rF2JBGLItTG+Be6A==", + "path": "microsoft.win32.registry/4.5.0", + "hashPath": "microsoft.win32.registry.4.5.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==", + "path": "newtonsoft.json/13.0.2", + "hashPath": "newtonsoft.json.13.0.2.nupkg.sha512" + }, + "System.Buffers/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A==", + "path": "system.buffers/4.5.0", + "hashPath": "system.buffers.4.5.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==", + "path": "system.componentmodel.annotations/4.5.0", + "hashPath": "system.componentmodel.annotations.4.5.0.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.2.25": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qpkqDHLNxGR1qBNrdnnPfJFfsKSWy3nUELC/BWxP8vwSaf8vVwecZzXOV4B52yOGit94g0pLWJEe30a4L1tE7g==", + "path": "system.linq.dynamic.core/1.2.25", + "hashPath": "system.linq.dynamic.core.1.2.25.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==", + "path": "system.security.accesscontrol/4.5.0", + "hashPath": "system.security.accesscontrol.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Cng/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==", + "path": "system.security.cryptography.cng/4.5.0", + "hashPath": "system.security.cryptography.cng.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-TGQX51gxpY3K3I6LJlE2LAftVlIMqJf0cBGhz68Y89jjk3LJCB6SrwiD+YN1fkqemBvWGs+GjyMJukl6d6goyQ==", + "path": "system.security.cryptography.pkcs/4.5.0", + "hashPath": "system.security.cryptography.pkcs.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Xml/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-i2Jn6rGXR63J0zIklImGRkDIJL4b1NfPSEbIVHBlqoIb12lfXIigCbDRpDmIEzwSo/v1U5y/rYJdzZYSyCWxvg==", + "path": "system.security.cryptography.xml/4.5.0", + "hashPath": "system.security.cryptography.xml.4.5.0.nupkg.sha512" + }, + "System.Security.Permissions/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==", + "path": "system.security.permissions/4.5.0", + "hashPath": "system.security.permissions.4.5.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "path": "system.security.principal.windows/4.5.0", + "hashPath": "system.security.principal.windows.4.5.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==", + "path": "system.text.encodings.web/4.5.0", + "hashPath": "system.text.encodings.web.4.5.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..4e15af0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb new file mode 100644 index 0000000..29203df Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.deps.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.deps.json new file mode 100644 index 0000000..3ef324b --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.deps.json @@ -0,0 +1,330 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "e-Suite.Modules.ContactsManager/1.0.0": { + "dependencies": { + "e-suite.API.Common": "2024.1.2.1-alpha" + }, + "runtime": { + "e-Suite.Modules.ContactsManager.dll": {} + } + }, + "e-suite.API.Common/2024.1.2.1-alpha": { + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "e-suite.Database.Core": "2024.1.2.5-alpha", + "e-suite.Utilities.Pagination": "2023.7.25.3", + "eSuite.Core": "2024.1.2.1-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.API.Common.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Audit/2024.1.2.2-alpha": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.9", + "Newtonsoft.Json": "13.0.2", + "System.Linq.Dynamic.Core": "1.2.25", + "eSuite.Core": "2024.1.2.1-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/2024.1.2.5-alpha": { + "dependencies": { + "e-suite.Database.Audit": "2024.1.2.2-alpha", + "e_suite.Nuget.PasswordHasher": "2024.1.2.1-alpha" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/2023.7.25.3": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.9" + }, + "runtime": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/2024.1.2.1-alpha": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0" + }, + "runtime": { + "lib/net8.0/eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/2024.1.2.1-alpha": { + "runtime": { + "lib/net8.0/e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.EntityFrameworkCore/7.0.9": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.9", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.9", + "Microsoft.Extensions.Caching.Memory": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "7.0.9.0", + "fileVersion": "7.0.923.31909" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.9": { + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "7.0.9.0", + "fileVersion": "7.0.923.31909" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.9": {}, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": {}, + "Microsoft.Extensions.Logging/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": {}, + "Microsoft.Extensions.Options/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Primitives/8.0.0": {}, + "Newtonsoft.Json/13.0.2": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.2.27524" + } + } + }, + "System.Linq.Dynamic.Core/1.2.25": { + "runtime": { + "lib/net7.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.2.25.0", + "fileVersion": "1.2.25.0" + } + } + } + } + }, + "libraries": { + "e-Suite.Modules.ContactsManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e-suite.API.Common/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-w4E9LNwvVEfAqUcK1J/DsandBQBsWCgNCZx394yh4Bz9ur8vS8ApqyVViWew9NbrJgyxeWLuTI35b00hB7l97g==", + "path": "e-suite.api.common/2024.1.2.1-alpha", + "hashPath": "e-suite.api.common.2024.1.2.1-alpha.nupkg.sha512" + }, + "e-suite.Database.Audit/2024.1.2.2-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kcgAX/Dwpmbe5s8xJkguax74DkAHPPDkHClZU13g17Uq9xA4fd3X7Yz93YqfBJ1y72pRNBnnBHABhgMEPAInKA==", + "path": "e-suite.database.audit/2024.1.2.2-alpha", + "hashPath": "e-suite.database.audit.2024.1.2.2-alpha.nupkg.sha512" + }, + "e-suite.Database.Core/2024.1.2.5-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ypg91t9N1kjeXKHw1nmZqctjYFQ4wZfZ/zGztkYfFXDclUmUgRvpPq0IRtMAnux5pJkmXz5mIAUP0UBNIu7VzA==", + "path": "e-suite.database.core/2024.1.2.5-alpha", + "hashPath": "e-suite.database.core.2024.1.2.5-alpha.nupkg.sha512" + }, + "e-suite.Utilities.Pagination/2023.7.25.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UM8RcXLFCva0hBtPGk4TN4boivylgpih5J3MlBcLMuIRZ9Bma/uE/pNCSk3IucremhhMOjaqEnGErXuxK3VyyA==", + "path": "e-suite.utilities.pagination/2023.7.25.3", + "hashPath": "e-suite.utilities.pagination.2023.7.25.3.nupkg.sha512" + }, + "eSuite.Core/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Ll/FLQldWCsM6KkRwkGbtvL+L7WAj/PxnPGIsA7QaD3Mum+VO+w6fBxgQJ2UcuQftLjL7kY1MszsC287EJEP9w==", + "path": "esuite.core/2024.1.2.1-alpha", + "hashPath": "esuite.core.2024.1.2.1-alpha.nupkg.sha512" + }, + "e_suite.Nuget.PasswordHasher/2024.1.2.1-alpha": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4dpQkbSVpLa+6436T1Z2X+FltHLYJK2r2UZxD0TrrVWc2A6HPReM/RB5ZrIxapRxGzYdvUzOlMfR+Q62hn1CAQ==", + "path": "e_suite.nuget.passwordhasher/2024.1.2.1-alpha", + "hashPath": "e_suite.nuget.passwordhasher.2024.1.2.1-alpha.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/7.0.9": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9YuCdQWuRAmYYHqwW1h5ukKMC1fmNvcVHdp3gb8zdHxwSQz7hkGpYOBEjm6dRXRmGRkpUyHL8rwUz4kd53Ev0A==", + "path": "microsoft.entityframeworkcore/7.0.9", + "hashPath": "microsoft.entityframeworkcore.7.0.9.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.9": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cfY6Fn7cnP/5pXndL8QYaey/B2nGn1fwze5aSaMJymmbqwqYzFiszHuWbsdVBCDYJc8ok7eB1m/nCc3/rltulQ==", + "path": "microsoft.entityframeworkcore.abstractions/7.0.9", + "hashPath": "microsoft.entityframeworkcore.abstractions.7.0.9.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.9": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VvqFD3DdML6LhPCAR/lG2xNX66juylC8v57yUAAYnUSdEUOMRi3lNoT4OrNdG0rere3UOQPhvVl5FH2QdyoF8Q==", + "path": "microsoft.entityframeworkcore.analyzers/7.0.9", + "hashPath": "microsoft.entityframeworkcore.analyzers.7.0.9.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IeimUd0TNbhB4ded3AbgBLQv2SnsiVugDyGV1MvspQFVlA07nDC7Zul7kcwH5jWN3JiTcp/ySE83AIJo8yfKjg==", + "path": "microsoft.extensions.caching.abstractions/7.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-xpidBs2KCE2gw1JrD0quHE72kvCaI3xFql5/Peb2GRtUuZX+dYPoK/NTdVMiM67Svym0M0Df9A3xyU0FbMQhHw==", + "path": "microsoft.extensions.caching.memory/7.0.0", + "hashPath": "microsoft.extensions.caching.memory.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Binder/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==", + "path": "microsoft.extensions.configuration.binder/8.0.0", + "hashPath": "microsoft.extensions.configuration.binder.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "path": "microsoft.extensions.logging/7.0.0", + "hashPath": "microsoft.extensions.logging.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "path": "microsoft.extensions.options/7.0.0", + "hashPath": "microsoft.extensions.options.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==", + "path": "newtonsoft.json/13.0.2", + "hashPath": "newtonsoft.json.13.0.2.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.2.25": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qpkqDHLNxGR1qBNrdnnPfJFfsKSWy3nUELC/BWxP8vwSaf8vVwecZzXOV4B52yOGit94g0pLWJEe30a4L1tE7g==", + "path": "system.linq.dynamic.core/1.2.25", + "hashPath": "system.linq.dynamic.core.1.2.25.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..f1a9899 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb new file mode 100644 index 0000000..a1ec9e8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/bin/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..ed92695 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/_IsIncrementalBuild b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/_IsIncrementalBuild new file mode 100644 index 0000000..9735daa --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/_IsIncrementalBuild @@ -0,0 +1 @@ +obj\Debug\net6.0\\_IsIncrementalBuild diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.AssemblyInfo.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.AssemblyInfo.cs new file mode 100644 index 0000000..ba322c4 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-Suite.Modules.ContactsManager")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-Suite.Modules.ContactsManager")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-Suite.Modules.ContactsManager")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache new file mode 100644 index 0000000..afb7cf8 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +c1fe5e5733016f99515ba9dd7a45fb781dc179183b56046e3f88a75e9fd78930 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..160930d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_Suite.Modules.ContactsManager +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.assets.cache new file mode 100644 index 0000000..2b68618 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache new file mode 100644 index 0000000..473e809 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..a806931 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +4ef34a1d1129827b3713b0a32705581c0db89287 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.FileListAbsolute.txt b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..6dc90e3 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.csproj.FileListAbsolute.txt @@ -0,0 +1,24 @@ +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.deps.json +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.AssemblyInfo.cs +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\refint\e-Suite.Modules.ContactsManager.dll +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\Colin Dawson\OneDrive\Code\Sun-Stragety\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\ref\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net6.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\refint\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net6.0\ref\e-Suite.Modules.ContactsManager.dll diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..4e15af0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb new file mode 100644 index 0000000..29203df Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/e-Suite.Modules.ContactsManager.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_038048a0-5bee-4a81-8df3-84104ce61c95.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_038048a0-5bee-4a81-8df3-84104ce61c95.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_038048a0-5bee-4a81-8df3-84104ce61c95.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_038048a0-5bee-4a81-8df3-84104ce61c95.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_038048a0-5bee-4a81-8df3-84104ce61c95.assets.cache new file mode 100644 index 0000000..3900ae7 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_038048a0-5bee-4a81-8df3-84104ce61c95.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1143bb64-b901-46ad-a260-df132cefe706.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1143bb64-b901-46ad-a260-df132cefe706.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1143bb64-b901-46ad-a260-df132cefe706.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1143bb64-b901-46ad-a260-df132cefe706.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1143bb64-b901-46ad-a260-df132cefe706.assets.cache new file mode 100644 index 0000000..f23de6c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1143bb64-b901-46ad-a260-df132cefe706.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1c2923bb-8cba-41aa-84ce-3b828b29be9d.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1c2923bb-8cba-41aa-84ce-3b828b29be9d.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1c2923bb-8cba-41aa-84ce-3b828b29be9d.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1c2923bb-8cba-41aa-84ce-3b828b29be9d.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1c2923bb-8cba-41aa-84ce-3b828b29be9d.assets.cache new file mode 100644 index 0000000..64f6979 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_1c2923bb-8cba-41aa-84ce-3b828b29be9d.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_2b53f959-6165-4ba0-a3cc-b0d98ef00076.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_2b53f959-6165-4ba0-a3cc-b0d98ef00076.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_2b53f959-6165-4ba0-a3cc-b0d98ef00076.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_2b53f959-6165-4ba0-a3cc-b0d98ef00076.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_2b53f959-6165-4ba0-a3cc-b0d98ef00076.assets.cache new file mode 100644 index 0000000..1c4fbdd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_2b53f959-6165-4ba0-a3cc-b0d98ef00076.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_3cc99790-340b-481c-b875-8a37d7df469d.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_3cc99790-340b-481c-b875-8a37d7df469d.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_3cc99790-340b-481c-b875-8a37d7df469d.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_3cc99790-340b-481c-b875-8a37d7df469d.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_3cc99790-340b-481c-b875-8a37d7df469d.assets.cache new file mode 100644 index 0000000..db40579 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_3cc99790-340b-481c-b875-8a37d7df469d.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_62166f9d-f90d-4353-a321-c6cec15a13f9.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_62166f9d-f90d-4353-a321-c6cec15a13f9.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_62166f9d-f90d-4353-a321-c6cec15a13f9.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_62166f9d-f90d-4353-a321-c6cec15a13f9.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_62166f9d-f90d-4353-a321-c6cec15a13f9.assets.cache new file mode 100644 index 0000000..604c7df Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_62166f9d-f90d-4353-a321-c6cec15a13f9.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_66568620-0d44-44de-80da-bfe78ef7781c.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_66568620-0d44-44de-80da-bfe78ef7781c.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_66568620-0d44-44de-80da-bfe78ef7781c.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_66568620-0d44-44de-80da-bfe78ef7781c.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_66568620-0d44-44de-80da-bfe78ef7781c.assets.cache new file mode 100644 index 0000000..fe84c66 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_66568620-0d44-44de-80da-bfe78ef7781c.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6a76d68a-bc9d-4479-9f8b-2c3b6c2bb447.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6a76d68a-bc9d-4479-9f8b-2c3b6c2bb447.assets.cache new file mode 100644 index 0000000..682f2f2 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6a76d68a-bc9d-4479-9f8b-2c3b6c2bb447.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6c77062f-6833-4d57-a455-987e1e65df5f.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6c77062f-6833-4d57-a455-987e1e65df5f.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6c77062f-6833-4d57-a455-987e1e65df5f.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6c77062f-6833-4d57-a455-987e1e65df5f.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6c77062f-6833-4d57-a455-987e1e65df5f.assets.cache new file mode 100644 index 0000000..c04950c Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_6c77062f-6833-4d57-a455-987e1e65df5f.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_72dfbb56-b3c6-498a-bacd-897917d2da0d.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_72dfbb56-b3c6-498a-bacd-897917d2da0d.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_72dfbb56-b3c6-498a-bacd-897917d2da0d.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_72dfbb56-b3c6-498a-bacd-897917d2da0d.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_72dfbb56-b3c6-498a-bacd-897917d2da0d.assets.cache new file mode 100644 index 0000000..d420cea Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_72dfbb56-b3c6-498a-bacd-897917d2da0d.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9114a40d-326e-497a-89c1-b5073593f52d.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9114a40d-326e-497a-89c1-b5073593f52d.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9114a40d-326e-497a-89c1-b5073593f52d.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9114a40d-326e-497a-89c1-b5073593f52d.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9114a40d-326e-497a-89c1-b5073593f52d.assets.cache new file mode 100644 index 0000000..89a9365 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9114a40d-326e-497a-89c1-b5073593f52d.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9395718b-91fb-4e51-bf69-214be4728901.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9395718b-91fb-4e51-bf69-214be4728901.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9395718b-91fb-4e51-bf69-214be4728901.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9395718b-91fb-4e51-bf69-214be4728901.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9395718b-91fb-4e51-bf69-214be4728901.assets.cache new file mode 100644 index 0000000..edbf9d9 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9395718b-91fb-4e51-bf69-214be4728901.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_99930a83-ab5b-4337-a582-ad1443e3a9c6.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_99930a83-ab5b-4337-a582-ad1443e3a9c6.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_99930a83-ab5b-4337-a582-ad1443e3a9c6.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_99930a83-ab5b-4337-a582-ad1443e3a9c6.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_99930a83-ab5b-4337-a582-ad1443e3a9c6.assets.cache new file mode 100644 index 0000000..b64d9dd Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_99930a83-ab5b-4337-a582-ad1443e3a9c6.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9a3a0681-45fa-437d-90db-b4ac16077adb.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9a3a0681-45fa-437d-90db-b4ac16077adb.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9a3a0681-45fa-437d-90db-b4ac16077adb.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9a3a0681-45fa-437d-90db-b4ac16077adb.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9a3a0681-45fa-437d-90db-b4ac16077adb.assets.cache new file mode 100644 index 0000000..0137bda Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9a3a0681-45fa-437d-90db-b4ac16077adb.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9b36af0b-3d94-4518-a3dc-7ee963725662.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9b36af0b-3d94-4518-a3dc-7ee963725662.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9b36af0b-3d94-4518-a3dc-7ee963725662.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9b36af0b-3d94-4518-a3dc-7ee963725662.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9b36af0b-3d94-4518-a3dc-7ee963725662.assets.cache new file mode 100644 index 0000000..4f5d1b3 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_9b36af0b-3d94-4518-a3dc-7ee963725662.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_baa69848-85d0-4d78-8009-961fa0003a6f.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_baa69848-85d0-4d78-8009-961fa0003a6f.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_baa69848-85d0-4d78-8009-961fa0003a6f.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_baa69848-85d0-4d78-8009-961fa0003a6f.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_baa69848-85d0-4d78-8009-961fa0003a6f.assets.cache new file mode 100644 index 0000000..8da4193 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_baa69848-85d0-4d78-8009-961fa0003a6f.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_bde282e4-5934-41a2-ae75-028aa0e53806.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_bde282e4-5934-41a2-ae75-028aa0e53806.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_bde282e4-5934-41a2-ae75-028aa0e53806.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_bde282e4-5934-41a2-ae75-028aa0e53806.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_bde282e4-5934-41a2-ae75-028aa0e53806.assets.cache new file mode 100644 index 0000000..9cd19e0 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_bde282e4-5934-41a2-ae75-028aa0e53806.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_c425a78b-adf7-4e7f-b44a-a692a88e77ff.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_c425a78b-adf7-4e7f-b44a-a692a88e77ff.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_c425a78b-adf7-4e7f-b44a-a692a88e77ff.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_c425a78b-adf7-4e7f-b44a-a692a88e77ff.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_c425a78b-adf7-4e7f-b44a-a692a88e77ff.assets.cache new file mode 100644 index 0000000..d3e8679 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_c425a78b-adf7-4e7f-b44a-a692a88e77ff.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_ce236a29-deab-4d69-9394-ee84443f6a96.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_ce236a29-deab-4d69-9394-ee84443f6a96.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_ce236a29-deab-4d69-9394-ee84443f6a96.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_ce236a29-deab-4d69-9394-ee84443f6a96.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_ce236a29-deab-4d69-9394-ee84443f6a96.assets.cache new file mode 100644 index 0000000..09b7383 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_ce236a29-deab-4d69-9394-ee84443f6a96.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_e71f0d79-c523-4418-bedc-d0e2289ae58e.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_e71f0d79-c523-4418-bedc-d0e2289ae58e.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_e71f0d79-c523-4418-bedc-d0e2289ae58e.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_e71f0d79-c523-4418-bedc-d0e2289ae58e.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_e71f0d79-c523-4418-bedc-d0e2289ae58e.assets.cache new file mode 100644 index 0000000..c0fac38 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_e71f0d79-c523-4418-bedc-d0e2289ae58e.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_fa1de30b-3bd1-4d5a-8354-f2573f665a70.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_fa1de30b-3bd1-4d5a-8354-f2573f665a70.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_fa1de30b-3bd1-4d5a-8354-f2573f665a70.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_fa1de30b-3bd1-4d5a-8354-f2573f665a70.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_fa1de30b-3bd1-4d5a-8354-f2573f665a70.assets.cache new file mode 100644 index 0000000..bdd6621 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/nCrunchTemp_fa1de30b-3bd1-4d5a-8354-f2573f665a70.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/ref/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/ref/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..7d1ee77 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/ref/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/refint/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/refint/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..7d1ee77 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net6.0/refint/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.AssemblyInfo.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.AssemblyInfo.cs new file mode 100644 index 0000000..ba322c4 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-Suite.Modules.ContactsManager")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-Suite.Modules.ContactsManager")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-Suite.Modules.ContactsManager")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache new file mode 100644 index 0000000..afb7cf8 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +c1fe5e5733016f99515ba9dd7a45fb781dc179183b56046e3f88a75e9fd78930 diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..08d182d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_Suite.Modules.ContactsManager +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.assets.cache new file mode 100644 index 0000000..79a1a15 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache new file mode 100644 index 0000000..1dca98e Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..b8aae01 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +0e8311bb251afb08d746b45494fa8361ff4d1ec4fb330ad310177f87fff91a2d diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.FileListAbsolute.txt b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..2044889 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.csproj.FileListAbsolute.txt @@ -0,0 +1,13 @@ +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\bin\Debug\net8.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.sourcelink.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\refint\e-Suite.Modules.ContactsManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\e-Suite.Modules.ContactsManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.ContactsManager\e-Suite.Modules.ContactsManager\obj\Debug\net8.0\ref\e-Suite.Modules.ContactsManager.dll diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..f1a9899 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb new file mode 100644 index 0000000..a1ec9e8 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.pdb differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.sourcelink.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.sourcelink.json new file mode 100644 index 0000000..8b82ea1 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/e-Suite.Modules.ContactsManager.sourcelink.json @@ -0,0 +1 @@ +{"documents":{"C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\*":"https://sunbranding.visualstudio.com/e-suite/_apis/git/repositories/e-suite.Modules.ContactsManager/items?api-version=1.0&versionType=commit&version=16d1f8478732acedbaca8ba574c4168abdb09918&path=/*"}} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_d39b3dc4-311c-4fbb-89e8-f6f7b0e2b2da.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_d39b3dc4-311c-4fbb-89e8-f6f7b0e2b2da.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_d39b3dc4-311c-4fbb-89e8-f6f7b0e2b2da.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_d39b3dc4-311c-4fbb-89e8-f6f7b0e2b2da.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_d39b3dc4-311c-4fbb-89e8-f6f7b0e2b2da.assets.cache new file mode 100644 index 0000000..1124dae Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_d39b3dc4-311c-4fbb-89e8-f6f7b0e2b2da.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_dc138b20-aa3f-4fd4-8ebf-75100e7d9a9c.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_dc138b20-aa3f-4fd4-8ebf-75100e7d9a9c.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_dc138b20-aa3f-4fd4-8ebf-75100e7d9a9c.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_dc138b20-aa3f-4fd4-8ebf-75100e7d9a9c.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_dc138b20-aa3f-4fd4-8ebf-75100e7d9a9c.assets.cache new file mode 100644 index 0000000..73a0fa5 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_dc138b20-aa3f-4fd4-8ebf-75100e7d9a9c.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_e98211e8-3d89-4679-bab1-85ea42846e27.GlobalUsings.g.cs b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_e98211e8-3d89-4679-bab1-85ea42846e27.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_e98211e8-3d89-4679-bab1-85ea42846e27.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_e98211e8-3d89-4679-bab1-85ea42846e27.assets.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_e98211e8-3d89-4679-bab1-85ea42846e27.assets.cache new file mode 100644 index 0000000..324a674 Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/nCrunchTemp_e98211e8-3d89-4679-bab1-85ea42846e27.assets.cache differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/ref/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/ref/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..22dc0cf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/ref/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/refint/e-Suite.Modules.ContactsManager.dll b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/refint/e-Suite.Modules.ContactsManager.dll new file mode 100644 index 0000000..22dc0cf Binary files /dev/null and b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/Debug/net8.0/refint/e-Suite.Modules.ContactsManager.dll differ diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.dgspec.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.dgspec.json new file mode 100644 index 0000000..53075f4 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.dgspec.json @@ -0,0 +1,76 @@ +{ + "format": 1, + "restore": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj": {} + }, + "projects": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "projectName": "e-Suite.Modules.ContactsManager", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\NuGet.Config", + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "e-suite.API.Common": { + "target": "Package", + "version": "[2023.5.23.21-beta, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.g.props b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.g.props new file mode 100644 index 0000000..62ed379 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.g.props @@ -0,0 +1,19 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\me\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages + PackageReference + 6.8.0 + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.g.targets b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.g.targets new file mode 100644 index 0000000..0dbeefd --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/e-Suite.Modules.ContactsManager.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/project.assets.json b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/project.assets.json new file mode 100644 index 0000000..f613384 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/project.assets.json @@ -0,0 +1,2183 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "e-suite.API.Common/2023.5.23.21-beta": { + "type": "package", + "dependencies": { + "e-suite.Database.Core": "2023.5.23.1-beta", + "e-suite.Utilities.Pagination": "2023.5.16.1-beta", + "eSuite.Core": "2023.3.31.1-beta" + }, + "compile": { + "lib/net6.0/e-suite.API.Common.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.API.Common.dll": {} + } + }, + "e-suite.Database.Audit/2023.5.23.1-beta": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.3", + "Newtonsoft.Json": "13.0.2", + "System.Linq.Dynamic.Core": "1.2.25", + "eSuite.Core": "2023.3.31.1-beta" + }, + "compile": { + "lib/net6.0/e-suite.Database.Audit.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Database.Audit.dll": {} + } + }, + "e-suite.Database.Core/2023.5.23.1-beta": { + "type": "package", + "dependencies": { + "e-suite.Database.Audit": "2023.5.23.1-beta", + "e_suite.Nuget.PasswordHasher": "2022.12.1.1" + }, + "compile": { + "lib/net6.0/e-suite.Database.Core.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Database.Core.dll": {} + } + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore": "7.0.5" + }, + "compile": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Utilities.Pagination.dll": {} + } + }, + "eSuite.Core/2023.3.31.1-beta": { + "type": "package", + "compile": { + "lib/net6.0/eSuite.Core.dll": {} + }, + "runtime": { + "lib/net6.0/eSuite.Core.dll": {} + } + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Identity": "2.2.0" + }, + "compile": { + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll": {} + }, + "runtime": { + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll": {} + } + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication.Core": "2.2.0", + "Microsoft.AspNetCore.DataProtection": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "Microsoft.Extensions.WebEncoders": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http": "2.2.0", + "Microsoft.AspNetCore.Http.Extensions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0" + }, + "compile": { + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.2.0", + "Microsoft.AspNetCore.DataProtection.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "Microsoft.Win32.Registry": "4.5.0", + "System.Security.Cryptography.Xml": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Hosting.Server.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.Hosting.Abstractions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.AspNetCore.WebUtilities": "2.2.0", + "Microsoft.Extensions.ObjectPool": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "Microsoft.Net.Http.Headers": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "2.2.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Buffers": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Authentication.Cookies": "2.2.0", + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0", + "Microsoft.Extensions.Identity.Core": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll": { + "related": ".xml" + } + } + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Net.Http.Headers": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll": { + "related": ".xml" + } + } + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.5", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.5", + "Microsoft.Extensions.Caching.Memory": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props": {} + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": { + "type": "package", + "compile": { + "lib/netstandard2.0/_._": {} + }, + "runtime": { + "lib/netstandard2.0/_._": {} + } + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "2.2.0", + "Microsoft.Extensions.Logging": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "System.ComponentModel.Annotations": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets": {} + } + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "System.Text.Encodings.Web": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0", + "System.Buffers": "4.5.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": {} + }, + "runtimeTargets": { + "runtimes/unix/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "Newtonsoft.Json/13.0.2": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.ComponentModel.Annotations/4.5.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Linq.Dynamic.Core/1.2.25": { + "type": "package", + "compile": { + "lib/net6.0/System.Linq.Dynamic.Core.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/System.Linq.Dynamic.Core.dll": { + "related": ".pdb;.xml" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "compile": { + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + } + }, + "System.Security.AccessControl/4.5.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0", + "System.Security.Principal.Windows": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": {} + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Cryptography.Cng/4.5.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll": {} + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Cryptography.Pkcs/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.Cryptography.Cng": "4.5.0" + }, + "compile": { + "ref/netcoreapp2.1/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": {} + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Cryptography.Xml/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.Cryptography.Pkcs": "4.5.0", + "System.Security.Permissions": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.Cryptography.Xml.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Cryptography.Xml.dll": {} + } + }, + "System.Security.Permissions/4.5.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "4.5.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.Permissions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Permissions.dll": {} + } + }, + "System.Security.Principal.Windows/4.5.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": {} + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Text.Encodings.Web/4.5.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/System.Text.Encodings.Web.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Text.Encodings.Web.dll": { + "related": ".xml" + } + } + } + } + }, + "libraries": { + "e-suite.API.Common/2023.5.23.21-beta": { + "sha512": "1867Fbx3Dc1fQSFC+oIBrJhb4xGy/oEX4b4Gx6efM9DPE3pzeulid0kNHv7UqBeaL6phdrsUyQu8lYrl2oYWgg==", + "type": "package", + "path": "e-suite.api.common/2023.5.23.21-beta", + "files": [ + ".nupkg.metadata", + "e-suite.api.common.2023.5.23.21-beta.nupkg.sha512", + "e-suite.api.common.nuspec", + "lib/net6.0/e-suite.API.Common.dll" + ] + }, + "e-suite.Database.Audit/2023.5.23.1-beta": { + "sha512": "8hM32LonYDw5fVS3KGR++vwmcgZgglMIjDF9apcy6Vz8HQEsrHd9lxvDT4U73bJBIyA34PIB+ioGiU4Q7uMxsw==", + "type": "package", + "path": "e-suite.database.audit/2023.5.23.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.database.audit.2023.5.23.1-beta.nupkg.sha512", + "e-suite.database.audit.nuspec", + "lib/net6.0/e-suite.Database.Audit.dll" + ] + }, + "e-suite.Database.Core/2023.5.23.1-beta": { + "sha512": "MpJA6iksaykv8HbXp4ZhGlezUvTlFv7RRCUmTRO6lxNF6BMK9lLeJEskaV4ivldNx4VPrvD1NINrjRR6ZDb9XQ==", + "type": "package", + "path": "e-suite.database.core/2023.5.23.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.database.core.2023.5.23.1-beta.nupkg.sha512", + "e-suite.database.core.nuspec", + "lib/net6.0/e-suite.Database.Core.dll" + ] + }, + "e-suite.Utilities.Pagination/2023.5.16.1-beta": { + "sha512": "0k9sjGp9YZpRUQaiyBkQpmslJTMOJ7ZR/f8Latc02Amcw953pB//CN+/XGGOO09FuxA3cWIsDQ9WsSEVU9iwxg==", + "type": "package", + "path": "e-suite.utilities.pagination/2023.5.16.1-beta", + "files": [ + ".nupkg.metadata", + "e-suite.utilities.pagination.2023.5.16.1-beta.nupkg.sha512", + "e-suite.utilities.pagination.nuspec", + "lib/net6.0/e-suite.Utilities.Pagination.dll" + ] + }, + "eSuite.Core/2023.3.31.1-beta": { + "sha512": "U1cmpMvZwNHk72F6C1r6ZEVuXVQDj10PxRGGG3g5iDWoGDEyCTImtKnZ4V2N/SesmZ87PCYrPsZdfVvjbHlJGA==", + "type": "package", + "path": "esuite.core/2023.3.31.1-beta", + "files": [ + ".nupkg.metadata", + "esuite.core.2023.3.31.1-beta.nupkg.sha512", + "esuite.core.nuspec", + "lib/net6.0/eSuite.Core.dll" + ] + }, + "e_suite.Nuget.PasswordHasher/2022.12.1.1": { + "sha512": "oKt0q1UISYgWj9v72yIEhvYkcdHiw8SNIQUkE+DZJ1FuVkCqPknzMiFIZY3FKGZOQf0XY1pgccazZPyl+06VWQ==", + "type": "package", + "path": "e_suite.nuget.passwordhasher/2022.12.1.1", + "files": [ + ".nupkg.metadata", + "e_suite.nuget.passwordhasher.2022.12.1.1.nupkg.sha512", + "e_suite.nuget.passwordhasher.nuspec", + "lib/net6.0/e-suite.Nuget.PasswordHasher.dll" + ] + }, + "Microsoft.AspNetCore.Authentication/2.2.0": { + "sha512": "b0R9X7L6zMqNsssKDvhYHuNi5x0s4DyHTeXybIAyGaitKiW1Q5aAGKdV2codHPiePv9yHfC9hAMyScXQ/xXhPw==", + "type": "package", + "path": "microsoft.aspnetcore.authentication/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.xml", + "microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.nuspec" + ] + }, + "Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": { + "sha512": "VloMLDJMf3n/9ic5lCBOa42IBYJgyB1JhzLsL68Zqg+2bEPWfGBj/xCJy/LrKTArN0coOcZp3wyVTZlx0y9pHQ==", + "type": "package", + "path": "microsoft.aspnetcore.authentication.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Abstractions.xml", + "microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Authentication.Cookies/2.2.0": { + "sha512": "Iar9VFlBHkZGdSG9ZUTmn6Q8Qg+6CtW5G/TyJI2F8B432TOH+nZlkU7O0W0byow6xsxqOYeTviSHz4cCJ3amfQ==", + "type": "package", + "path": "microsoft.aspnetcore.authentication.cookies/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Cookies.xml", + "microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.cookies.nuspec" + ] + }, + "Microsoft.AspNetCore.Authentication.Core/2.2.0": { + "sha512": "XlVJzJ5wPOYW+Y0J6Q/LVTEyfS4ssLXmt60T0SPP+D8abVhBTl+cgw2gDHlyKYIkcJg7btMVh383NDkMVqD/fg==", + "type": "package", + "path": "microsoft.aspnetcore.authentication.core/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Authentication.Core.xml", + "microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.authentication.core.nuspec" + ] + }, + "Microsoft.AspNetCore.Cryptography.Internal/2.2.0": { + "sha512": "GXmMD8/vuTLPLvKzKEPz/4vapC5e0cwx1tUVd83ePRyWF9CCrn/pg4/1I+tGkQqFLPvi3nlI2QtPtC6MQN8Nww==", + "type": "package", + "path": "microsoft.aspnetcore.cryptography.internal/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.Internal.xml", + "microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.cryptography.internal.nuspec" + ] + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation/2.2.0": { + "sha512": "NCY0PH3nrFYbhqiq72rwWsUXlV4OAE0MOukvGvIBOTnEPMC1yVL42k1DXLnaIu+c0yfMAxIIG9Iuaykp9BQQQw==", + "type": "package", + "path": "microsoft.aspnetcore.cryptography.keyderivation/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll", + "lib/netcoreapp2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.xml", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Cryptography.KeyDerivation.xml", + "microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.cryptography.keyderivation.nuspec" + ] + }, + "Microsoft.AspNetCore.DataProtection/2.2.0": { + "sha512": "G6dvu5Nd2vjpYbzazZ//qBFbSEf2wmBUbyAR7E4AwO3gWjhoJD5YxpThcGJb7oE3VUcW65SVMXT+cPCiiBg8Sg==", + "type": "package", + "path": "microsoft.aspnetcore.dataprotection/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.xml", + "microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.dataprotection.nuspec" + ] + }, + "Microsoft.AspNetCore.DataProtection.Abstractions/2.2.0": { + "sha512": "seANFXmp8mb5Y12m1ShiElJ3ZdOT3mBN3wA1GPhHJIvZ/BxOCPyqEOR+810OWsxEZwA5r5fDRNpG/CqiJmQnJg==", + "type": "package", + "path": "microsoft.aspnetcore.dataprotection.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.DataProtection.Abstractions.xml", + "microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.dataprotection.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Hosting.Abstractions/2.2.0": { + "sha512": "ubycklv+ZY7Kutdwuy1W4upWcZ6VFR8WUXU7l7B2+mvbDBBPAcfpi+E+Y5GFe+Q157YfA3C49D2GCjAZc7Mobw==", + "type": "package", + "path": "microsoft.aspnetcore.hosting.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Abstractions.xml", + "microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.hosting.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions/2.2.0": { + "sha512": "1PMijw8RMtuQF60SsD/JlKtVfvh4NORAhF4wjysdABhlhTrYmtgssqyncR0Stq5vqtjplZcj6kbT4LRTglt9IQ==", + "type": "package", + "path": "microsoft.aspnetcore.hosting.server.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.xml", + "microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.hosting.server.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Http/2.2.0": { + "sha512": "YogBSMotWPAS/X5967pZ+yyWPQkThxhmzAwyCHCSSldzYBkW5W5d6oPfBaPqQOnSHYTpSOSOkpZoAce0vwb6+A==", + "type": "package", + "path": "microsoft.aspnetcore.http/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.xml", + "microsoft.aspnetcore.http.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.nuspec" + ] + }, + "Microsoft.AspNetCore.Http.Abstractions/2.2.0": { + "sha512": "Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==", + "type": "package", + "path": "microsoft.aspnetcore.http.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.xml", + "microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.abstractions.nuspec" + ] + }, + "Microsoft.AspNetCore.Http.Extensions/2.2.0": { + "sha512": "2DgZ9rWrJtuR7RYiew01nGRzuQBDaGHGmK56Rk54vsLLsCdzuFUPqbDTJCS1qJQWTbmbIQ9wGIOjpxA1t0l7/w==", + "type": "package", + "path": "microsoft.aspnetcore.http.extensions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Extensions.xml", + "microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.extensions.nuspec" + ] + }, + "Microsoft.AspNetCore.Http.Features/2.2.0": { + "sha512": "ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==", + "type": "package", + "path": "microsoft.aspnetcore.http.features/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.xml", + "microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.http.features.nuspec" + ] + }, + "Microsoft.AspNetCore.Identity/2.2.0": { + "sha512": "F16BKeS96wKhyIyhaFR7m8kRIwIvPUW9Dx7IlGWmu2IIwnUDCdo+2z7IrWKA8r77pZQ1UE9kYcBPg5456YdAIA==", + "type": "package", + "path": "microsoft.aspnetcore.identity/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.Identity.xml", + "microsoft.aspnetcore.identity.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.identity.nuspec" + ] + }, + "Microsoft.AspNetCore.WebUtilities/2.2.0": { + "sha512": "9ErxAAKaDzxXASB/b5uLEkLgUWv1QbeVxyJYEHQwMaxXOeFFVkQxiq8RyfVcifLU7NR0QY0p3acqx4ZpYfhHDg==", + "type": "package", + "path": "microsoft.aspnetcore.webutilities/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll", + "lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.xml", + "microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512", + "microsoft.aspnetcore.webutilities.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore/7.0.5": { + "sha512": "RXbRLHHWP2Z3pq8qcL5nQ6LPeoOyp8hasM5bd0Te8PiQi3RjWQR4tcbdY5XMqQ+oTO9wA8/RLhZRn/hnxlTDnQ==", + "type": "package", + "path": "microsoft.entityframeworkcore/7.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props", + "lib/net6.0/Microsoft.EntityFrameworkCore.dll", + "lib/net6.0/Microsoft.EntityFrameworkCore.xml", + "microsoft.entityframeworkcore.7.0.5.nupkg.sha512", + "microsoft.entityframeworkcore.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore.Abstractions/7.0.5": { + "sha512": "iwQso+hFRsEWjhH2WsEQj1D2QE5BlEXiXEt6A3SlYTPRPdZsyTNDeDDEdtxL+H/UJPQgQYY+9SMMRcEiXBmCAA==", + "type": "package", + "path": "microsoft.entityframeworkcore.abstractions/7.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll", + "lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.xml", + "microsoft.entityframeworkcore.abstractions.7.0.5.nupkg.sha512", + "microsoft.entityframeworkcore.abstractions.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore.Analyzers/7.0.5": { + "sha512": "yMLM/aK1MikVqpjxd7PJ1Pjgztd3VAd26ZHxyjxG3RPeM9cHjvS5tCg9kAAayR6eHmBg0ffZsHdT28WfA5tTlA==", + "type": "package", + "path": "microsoft.entityframeworkcore.analyzers/7.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "analyzers/dotnet/cs/Microsoft.EntityFrameworkCore.Analyzers.dll", + "lib/netstandard2.0/_._", + "microsoft.entityframeworkcore.analyzers.7.0.5.nupkg.sha512", + "microsoft.entityframeworkcore.analyzers.nuspec" + ] + }, + "Microsoft.Extensions.Caching.Abstractions/7.0.0": { + "sha512": "IeimUd0TNbhB4ded3AbgBLQv2SnsiVugDyGV1MvspQFVlA07nDC7Zul7kcwH5jWN3JiTcp/ySE83AIJo8yfKjg==", + "type": "package", + "path": "microsoft.extensions.caching.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.xml", + "microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.caching.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Caching.Memory/7.0.0": { + "sha512": "xpidBs2KCE2gw1JrD0quHE72kvCaI3xFql5/Peb2GRtUuZX+dYPoK/NTdVMiM67Svym0M0Df9A3xyU0FbMQhHw==", + "type": "package", + "path": "microsoft.extensions.caching.memory/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Memory.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Memory.targets", + "lib/net462/Microsoft.Extensions.Caching.Memory.dll", + "lib/net462/Microsoft.Extensions.Caching.Memory.xml", + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net6.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/net7.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net7.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.xml", + "microsoft.extensions.caching.memory.7.0.0.nupkg.sha512", + "microsoft.extensions.caching.memory.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Abstractions/2.2.0": { + "sha512": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", + "type": "package", + "path": "microsoft.extensions.configuration.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512", + "microsoft.extensions.configuration.abstractions.nuspec" + ] + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "sha512": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.targets", + "lib/net462/Microsoft.Extensions.DependencyInjection.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.xml", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.xml", + "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512", + "microsoft.extensions.dependencyinjection.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "sha512": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.dependencyinjection.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.FileProviders.Abstractions/2.2.0": { + "sha512": "EcnaSsPTqx2MGnHrmWOD0ugbuuqVT8iICqSqPzi45V5/MA1LjUNb0kwgcxBGqizV1R+WeBK7/Gw25Jzkyk9bIw==", + "type": "package", + "path": "microsoft.extensions.fileproviders.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.xml", + "microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512", + "microsoft.extensions.fileproviders.abstractions.nuspec" + ] + }, + "Microsoft.Extensions.Hosting.Abstractions/2.2.0": { + "sha512": "+k4AEn68HOJat5gj1TWa6X28WlirNQO9sPIIeQbia+91n03esEtMSSoekSTpMjUzjqtJWQN3McVx0GvSPFHF/Q==", + "type": "package", + "path": "microsoft.extensions.hosting.abstractions/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.xml", + "microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512", + "microsoft.extensions.hosting.abstractions.nuspec" + ] + }, + "Microsoft.Extensions.Identity.Core/2.2.0": { + "sha512": "/C+Valwg8IeUwDIunusittHivA9iyf82Jr1yeUFWO2zH2mDMMeYgjRyDLZqfL/7Vq94PEQsgv1XAaDfAX8msMw==", + "type": "package", + "path": "microsoft.extensions.identity.core/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.dll", + "lib/netstandard2.0/Microsoft.Extensions.Identity.Core.xml", + "microsoft.extensions.identity.core.2.2.0.nupkg.sha512", + "microsoft.extensions.identity.core.nuspec" + ] + }, + "Microsoft.Extensions.Logging/7.0.0": { + "sha512": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "type": "package", + "path": "microsoft.extensions.logging/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Logging.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.targets", + "lib/net462/Microsoft.Extensions.Logging.dll", + "lib/net462/Microsoft.Extensions.Logging.xml", + "lib/net6.0/Microsoft.Extensions.Logging.dll", + "lib/net6.0/Microsoft.Extensions.Logging.xml", + "lib/net7.0/Microsoft.Extensions.Logging.dll", + "lib/net7.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.1/Microsoft.Extensions.Logging.xml", + "microsoft.extensions.logging.7.0.0.nupkg.sha512", + "microsoft.extensions.logging.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "sha512": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.ObjectPool/2.2.0": { + "sha512": "gA8H7uQOnM5gb+L0uTNjViHYr+hRDqCdfugheGo/MxQnuHzmhhzCBTIPm19qL1z1Xe0NEMabfcOBGv9QghlZ8g==", + "type": "package", + "path": "microsoft.extensions.objectpool/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll", + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.xml", + "microsoft.extensions.objectpool.2.2.0.nupkg.sha512", + "microsoft.extensions.objectpool.nuspec" + ] + }, + "Microsoft.Extensions.Options/7.0.0": { + "sha512": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "type": "package", + "path": "microsoft.extensions.options/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Options.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Options.targets", + "lib/net462/Microsoft.Extensions.Options.dll", + "lib/net462/Microsoft.Extensions.Options.xml", + "lib/net6.0/Microsoft.Extensions.Options.dll", + "lib/net6.0/Microsoft.Extensions.Options.xml", + "lib/net7.0/Microsoft.Extensions.Options.dll", + "lib/net7.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.0/Microsoft.Extensions.Options.dll", + "lib/netstandard2.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.1/Microsoft.Extensions.Options.dll", + "lib/netstandard2.1/Microsoft.Extensions.Options.xml", + "microsoft.extensions.options.7.0.0.nupkg.sha512", + "microsoft.extensions.options.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "sha512": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==", + "type": "package", + "path": "microsoft.extensions.primitives/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Primitives.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Primitives.targets", + "lib/net462/Microsoft.Extensions.Primitives.dll", + "lib/net462/Microsoft.Extensions.Primitives.xml", + "lib/net6.0/Microsoft.Extensions.Primitives.dll", + "lib/net6.0/Microsoft.Extensions.Primitives.xml", + "lib/net7.0/Microsoft.Extensions.Primitives.dll", + "lib/net7.0/Microsoft.Extensions.Primitives.xml", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.dll", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.xml", + "microsoft.extensions.primitives.7.0.0.nupkg.sha512", + "microsoft.extensions.primitives.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.WebEncoders/2.2.0": { + "sha512": "V8XcqYcpcdBAxUhLeyYcuKmxu4CtNQA9IphTnARpQGhkop4A93v2XgM3AtaVVJo3H2cDWxWM6aeO8HxkifREqw==", + "type": "package", + "path": "microsoft.extensions.webencoders/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.dll", + "lib/netstandard2.0/Microsoft.Extensions.WebEncoders.xml", + "microsoft.extensions.webencoders.2.2.0.nupkg.sha512", + "microsoft.extensions.webencoders.nuspec" + ] + }, + "Microsoft.Net.Http.Headers/2.2.0": { + "sha512": "iZNkjYqlo8sIOI0bQfpsSoMTmB/kyvmV2h225ihyZT33aTp48ZpF6qYnXxzSXmHt8DpBAwBTX+1s1UFLbYfZKg==", + "type": "package", + "path": "microsoft.net.http.headers/2.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Net.Http.Headers.dll", + "lib/netstandard2.0/Microsoft.Net.Http.Headers.xml", + "microsoft.net.http.headers.2.2.0.nupkg.sha512", + "microsoft.net.http.headers.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/2.0.0": { + "sha512": "VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==", + "type": "package", + "path": "microsoft.netcore.platforms/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.2.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/4.5.0": { + "sha512": "+FWlwd//+Tt56316p00hVePBCouXyEzT86Jb3+AuRotTND0IYn0OO3obs1gnQEs/txEnt+rF2JBGLItTG+Be6A==", + "type": "package", + "path": "microsoft.win32.registry/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "microsoft.win32.registry.4.5.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/unix/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Newtonsoft.Json/13.0.2": { + "sha512": "R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==", + "type": "package", + "path": "newtonsoft.json/13.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.2.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "System.Buffers/4.5.0": { + "sha512": "pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A==", + "type": "package", + "path": "system.buffers/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.0.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.ComponentModel.Annotations/4.5.0": { + "sha512": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==", + "type": "package", + "path": "system.componentmodel.annotations/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net461/System.ComponentModel.Annotations.dll", + "lib/netcore50/System.ComponentModel.Annotations.dll", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.4/System.ComponentModel.Annotations.dll", + "lib/netstandard2.0/System.ComponentModel.Annotations.dll", + "lib/portable-net45+win8/_._", + "lib/uap10.0.16299/_._", + "lib/win8/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net461/System.ComponentModel.Annotations.dll", + "ref/net461/System.ComponentModel.Annotations.xml", + "ref/netcore50/System.ComponentModel.Annotations.dll", + "ref/netcore50/System.ComponentModel.Annotations.xml", + "ref/netcore50/de/System.ComponentModel.Annotations.xml", + "ref/netcore50/es/System.ComponentModel.Annotations.xml", + "ref/netcore50/fr/System.ComponentModel.Annotations.xml", + "ref/netcore50/it/System.ComponentModel.Annotations.xml", + "ref/netcore50/ja/System.ComponentModel.Annotations.xml", + "ref/netcore50/ko/System.ComponentModel.Annotations.xml", + "ref/netcore50/ru/System.ComponentModel.Annotations.xml", + "ref/netcore50/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netcore50/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.ComponentModel.Annotations.dll", + "ref/netstandard1.1/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/System.ComponentModel.Annotations.dll", + "ref/netstandard1.3/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/System.ComponentModel.Annotations.dll", + "ref/netstandard1.4/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard2.0/System.ComponentModel.Annotations.dll", + "ref/netstandard2.0/System.ComponentModel.Annotations.xml", + "ref/portable-net45+win8/_._", + "ref/uap10.0.16299/_._", + "ref/win8/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.componentmodel.annotations.4.5.0.nupkg.sha512", + "system.componentmodel.annotations.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Linq.Dynamic.Core/1.2.25": { + "sha512": "qpkqDHLNxGR1qBNrdnnPfJFfsKSWy3nUELC/BWxP8vwSaf8vVwecZzXOV4B52yOGit94g0pLWJEe30a4L1tE7g==", + "type": "package", + "path": "system.linq.dynamic.core/1.2.25", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net35/System.Linq.Dynamic.Core.dll", + "lib/net35/System.Linq.Dynamic.Core.pdb", + "lib/net35/System.Linq.Dynamic.Core.xml", + "lib/net40/System.Linq.Dynamic.Core.dll", + "lib/net40/System.Linq.Dynamic.Core.pdb", + "lib/net40/System.Linq.Dynamic.Core.xml", + "lib/net45/System.Linq.Dynamic.Core.dll", + "lib/net45/System.Linq.Dynamic.Core.pdb", + "lib/net45/System.Linq.Dynamic.Core.xml", + "lib/net452/System.Linq.Dynamic.Core.dll", + "lib/net452/System.Linq.Dynamic.Core.pdb", + "lib/net452/System.Linq.Dynamic.Core.xml", + "lib/net46/System.Linq.Dynamic.Core.dll", + "lib/net46/System.Linq.Dynamic.Core.pdb", + "lib/net46/System.Linq.Dynamic.Core.xml", + "lib/net5.0/System.Linq.Dynamic.Core.dll", + "lib/net5.0/System.Linq.Dynamic.Core.pdb", + "lib/net5.0/System.Linq.Dynamic.Core.xml", + "lib/net6.0/System.Linq.Dynamic.Core.dll", + "lib/net6.0/System.Linq.Dynamic.Core.pdb", + "lib/net6.0/System.Linq.Dynamic.Core.xml", + "lib/net7.0/System.Linq.Dynamic.Core.dll", + "lib/net7.0/System.Linq.Dynamic.Core.pdb", + "lib/net7.0/System.Linq.Dynamic.Core.xml", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.dll", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.pdb", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.xml", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.dll", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.pdb", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.xml", + "lib/netstandard1.3/System.Linq.Dynamic.Core.dll", + "lib/netstandard1.3/System.Linq.Dynamic.Core.pdb", + "lib/netstandard1.3/System.Linq.Dynamic.Core.xml", + "lib/netstandard2.0/System.Linq.Dynamic.Core.dll", + "lib/netstandard2.0/System.Linq.Dynamic.Core.pdb", + "lib/netstandard2.0/System.Linq.Dynamic.Core.xml", + "lib/netstandard2.1/System.Linq.Dynamic.Core.dll", + "lib/netstandard2.1/System.Linq.Dynamic.Core.pdb", + "lib/netstandard2.1/System.Linq.Dynamic.Core.xml", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.dll", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.pdb", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.pri", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.xml", + "logo.png", + "system.linq.dynamic.core.1.2.25.nupkg.sha512", + "system.linq.dynamic.core.nuspec" + ] + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "sha512": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net461/System.Runtime.CompilerServices.Unsafe.xml", + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Security.AccessControl/4.5.0": { + "sha512": "vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==", + "type": "package", + "path": "system.security.accesscontrol/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.4.5.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Cryptography.Cng/4.5.0": { + "sha512": "WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==", + "type": "package", + "path": "system.security.cryptography.cng/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Cng.dll", + "lib/net461/System.Security.Cryptography.Cng.dll", + "lib/net462/System.Security.Cryptography.Cng.dll", + "lib/net47/System.Security.Cryptography.Cng.dll", + "lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll", + "lib/netstandard1.3/System.Security.Cryptography.Cng.dll", + "lib/netstandard1.4/System.Security.Cryptography.Cng.dll", + "lib/netstandard1.6/System.Security.Cryptography.Cng.dll", + "lib/netstandard2.0/System.Security.Cryptography.Cng.dll", + "lib/uap10.0.16299/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Cng.dll", + "ref/net461/System.Security.Cryptography.Cng.dll", + "ref/net461/System.Security.Cryptography.Cng.xml", + "ref/net462/System.Security.Cryptography.Cng.dll", + "ref/net462/System.Security.Cryptography.Cng.xml", + "ref/net47/System.Security.Cryptography.Cng.dll", + "ref/net47/System.Security.Cryptography.Cng.xml", + "ref/netcoreapp2.0/System.Security.Cryptography.Cng.dll", + "ref/netcoreapp2.0/System.Security.Cryptography.Cng.xml", + "ref/netcoreapp2.1/System.Security.Cryptography.Cng.dll", + "ref/netcoreapp2.1/System.Security.Cryptography.Cng.xml", + "ref/netstandard1.3/System.Security.Cryptography.Cng.dll", + "ref/netstandard1.4/System.Security.Cryptography.Cng.dll", + "ref/netstandard1.6/System.Security.Cryptography.Cng.dll", + "ref/netstandard2.0/System.Security.Cryptography.Cng.dll", + "ref/netstandard2.0/System.Security.Cryptography.Cng.xml", + "ref/uap10.0.16299/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "runtimes/win/lib/net46/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/net461/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/net462/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/net47/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netstandard1.4/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/netstandard1.6/System.Security.Cryptography.Cng.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.cryptography.cng.4.5.0.nupkg.sha512", + "system.security.cryptography.cng.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Cryptography.Pkcs/4.5.0": { + "sha512": "TGQX51gxpY3K3I6LJlE2LAftVlIMqJf0cBGhz68Y89jjk3LJCB6SrwiD+YN1fkqemBvWGs+GjyMJukl6d6goyQ==", + "type": "package", + "path": "system.security.cryptography.pkcs/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Cryptography.Pkcs.dll", + "lib/net461/System.Security.Cryptography.Pkcs.dll", + "lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll", + "lib/netstandard1.3/System.Security.Cryptography.Pkcs.dll", + "lib/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "ref/net46/System.Security.Cryptography.Pkcs.dll", + "ref/net461/System.Security.Cryptography.Pkcs.dll", + "ref/net461/System.Security.Cryptography.Pkcs.xml", + "ref/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll", + "ref/netcoreapp2.1/System.Security.Cryptography.Pkcs.xml", + "ref/netstandard1.3/System.Security.Cryptography.Pkcs.dll", + "ref/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "ref/netstandard2.0/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/net46/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/net461/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netstandard1.3/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "system.security.cryptography.pkcs.4.5.0.nupkg.sha512", + "system.security.cryptography.pkcs.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Cryptography.Xml/4.5.0": { + "sha512": "i2Jn6rGXR63J0zIklImGRkDIJL4b1NfPSEbIVHBlqoIb12lfXIigCbDRpDmIEzwSo/v1U5y/rYJdzZYSyCWxvg==", + "type": "package", + "path": "system.security.cryptography.xml/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Security.Cryptography.Xml.dll", + "lib/netstandard2.0/System.Security.Cryptography.Xml.dll", + "ref/net461/System.Security.Cryptography.Xml.dll", + "ref/net461/System.Security.Cryptography.Xml.xml", + "ref/netstandard2.0/System.Security.Cryptography.Xml.dll", + "ref/netstandard2.0/System.Security.Cryptography.Xml.xml", + "system.security.cryptography.xml.4.5.0.nupkg.sha512", + "system.security.cryptography.xml.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Permissions/4.5.0": { + "sha512": "9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==", + "type": "package", + "path": "system.security.permissions/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Security.Permissions.dll", + "lib/netstandard2.0/System.Security.Permissions.dll", + "ref/net461/System.Security.Permissions.dll", + "ref/net461/System.Security.Permissions.xml", + "ref/netstandard2.0/System.Security.Permissions.dll", + "ref/netstandard2.0/System.Security.Permissions.xml", + "system.security.permissions.4.5.0.nupkg.sha512", + "system.security.permissions.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/4.5.0": { + "sha512": "U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "type": "package", + "path": "system.security.principal.windows/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.4.5.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Text.Encodings.Web/4.5.0": { + "sha512": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==", + "type": "package", + "path": "system.text.encodings.web/4.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/System.Text.Encodings.Web.dll", + "lib/netstandard1.0/System.Text.Encodings.Web.xml", + "lib/netstandard2.0/System.Text.Encodings.Web.dll", + "lib/netstandard2.0/System.Text.Encodings.Web.xml", + "system.text.encodings.web.4.5.0.nupkg.sha512", + "system.text.encodings.web.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "e-suite.API.Common >= 2023.5.23.21-beta" + ] + }, + "packageFolders": { + "C:\\Users\\me\\.nuget\\packages\\": {}, + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "projectName": "e-Suite.Modules.ContactsManager", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\NuGet.Config", + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "e-suite.API.Common": { + "target": "Package", + "version": "[2023.5.23.21-beta, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/project.nuget.cache b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/project.nuget.cache new file mode 100644 index 0000000..397c3d5 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-Suite.Modules.ContactsManager/obj/project.nuget.cache @@ -0,0 +1,63 @@ +{ + "version": 2, + "dgSpecHash": "TwjsoVUoblN2BiKyOXIRGIkRecMeBDgBjNF9es+rjgjHq22kfVzD9ag3ZtUFTUiU52IVlXnl+YXBvTQYTv7/8w==", + "success": true, + "projectFilePath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager\\e-Suite.Modules.ContactsManager.csproj", + "expectedPackageFiles": [ + "C:\\Users\\me\\.nuget\\packages\\e-suite.api.common\\2023.5.23.21-beta\\e-suite.api.common.2023.5.23.21-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.database.audit\\2023.5.23.1-beta\\e-suite.database.audit.2023.5.23.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.database.core\\2023.5.23.1-beta\\e-suite.database.core.2023.5.23.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e-suite.utilities.pagination\\2023.5.16.1-beta\\e-suite.utilities.pagination.2023.5.16.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\esuite.core\\2023.3.31.1-beta\\esuite.core.2023.3.31.1-beta.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\e_suite.nuget.passwordhasher\\2022.12.1.1\\e_suite.nuget.passwordhasher.2022.12.1.1.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication\\2.2.0\\microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication.abstractions\\2.2.0\\microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication.cookies\\2.2.0\\microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.authentication.core\\2.2.0\\microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.cryptography.internal\\2.2.0\\microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.cryptography.keyderivation\\2.2.0\\microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.dataprotection\\2.2.0\\microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.dataprotection.abstractions\\2.2.0\\microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.hosting.abstractions\\2.2.0\\microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.hosting.server.abstractions\\2.2.0\\microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http\\2.2.0\\microsoft.aspnetcore.http.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http.abstractions\\2.2.0\\microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http.extensions\\2.2.0\\microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.http.features\\2.2.0\\microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.identity\\2.2.0\\microsoft.aspnetcore.identity.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.aspnetcore.webutilities\\2.2.0\\microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore\\7.0.5\\microsoft.entityframeworkcore.7.0.5.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore.abstractions\\7.0.5\\microsoft.entityframeworkcore.abstractions.7.0.5.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore.analyzers\\7.0.5\\microsoft.entityframeworkcore.analyzers.7.0.5.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\7.0.0\\microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.caching.memory\\7.0.0\\microsoft.extensions.caching.memory.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\2.2.0\\microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\7.0.0\\microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\7.0.0\\microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.fileproviders.abstractions\\2.2.0\\microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.hosting.abstractions\\2.2.0\\microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.identity.core\\2.2.0\\microsoft.extensions.identity.core.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.logging\\7.0.0\\microsoft.extensions.logging.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\7.0.0\\microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.objectpool\\2.2.0\\microsoft.extensions.objectpool.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.options\\7.0.0\\microsoft.extensions.options.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.primitives\\7.0.0\\microsoft.extensions.primitives.7.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.webencoders\\2.2.0\\microsoft.extensions.webencoders.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.net.http.headers\\2.2.0\\microsoft.net.http.headers.2.2.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.netcore.platforms\\2.0.0\\microsoft.netcore.platforms.2.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.win32.registry\\4.5.0\\microsoft.win32.registry.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\newtonsoft.json\\13.0.2\\newtonsoft.json.13.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.buffers\\4.5.0\\system.buffers.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.componentmodel.annotations\\4.5.0\\system.componentmodel.annotations.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.linq.dynamic.core\\1.2.25\\system.linq.dynamic.core.1.2.25.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.runtime.compilerservices.unsafe\\6.0.0\\system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.accesscontrol\\4.5.0\\system.security.accesscontrol.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.cryptography.cng\\4.5.0\\system.security.cryptography.cng.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.cryptography.pkcs\\4.5.0\\system.security.cryptography.pkcs.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.cryptography.xml\\4.5.0\\system.security.cryptography.xml.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.permissions\\4.5.0\\system.security.permissions.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.security.principal.windows\\4.5.0\\system.security.principal.windows.4.5.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.text.encodings.web\\4.5.0\\system.text.encodings.web.4.5.0.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/e-suite.Modules.ContactsManager/e-suite.Modules.ContactsManager.v3.ncrunchsolution.user b/e-suite.Modules.ContactsManager/e-suite.Modules.ContactsManager.v3.ncrunchsolution.user new file mode 100644 index 0000000..00783d7 --- /dev/null +++ b/e-suite.Modules.ContactsManager/e-suite.Modules.ContactsManager.v3.ncrunchsolution.user @@ -0,0 +1,8 @@ + + + True + Run all tests automatically [Global] + 14.0816326141357% + 50% + + \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/.gitattributes b/e-suite.Modules.CustomFieldsManager/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/.gitignore b/e-suite.Modules.CustomFieldsManager/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.CustomFieldsManager/.runsettings b/e-suite.Modules.CustomFieldsManager/.runsettings new file mode 100644 index 0000000..62628bc --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/.runsettings @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + .*microsoft.testplatform.* + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/README.md b/e-suite.Modules.CustomFieldsManager/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/azure-pipelinse.yml b/e-suite.Modules.CustomFieldsManager/azure-pipelinse.yml new file mode 100644 index 0000000..86886b0 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/azure-pipelinse.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.sln b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.sln new file mode 100644 index 0000000..1bf8ebc --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.CustomFieldsManager", "e-suite.Modules.CustomFieldsManager\e-suite.Modules.CustomFieldsManager.csproj", "{F9B17E14-69E6-42AA-AC96-7832A513E555}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e_suite.Modules.CustomFieldManagerUnitTests", "e_suite.Modules.CusomFieldManagerUnitTest\e_suite.Modules.CustomFieldManagerUnitTests.csproj", "{3AB0B90B-4429-4858-BA06-82A960CDAF69}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{77E71695-7E61-4995-863B-5D2278E09EAE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{DCAD7E50-16BA-4E57-B32E-48E96792E4DA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F9B17E14-69E6-42AA-AC96-7832A513E555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9B17E14-69E6-42AA-AC96-7832A513E555}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9B17E14-69E6-42AA-AC96-7832A513E555}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9B17E14-69E6-42AA-AC96-7832A513E555}.Release|Any CPU.Build.0 = Release|Any CPU + {3AB0B90B-4429-4858-BA06-82A960CDAF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AB0B90B-4429-4858-BA06-82A960CDAF69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AB0B90B-4429-4858-BA06-82A960CDAF69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AB0B90B-4429-4858-BA06-82A960CDAF69}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3AB0B90B-4429-4858-BA06-82A960CDAF69} = {DCAD7E50-16BA-4E57-B32E-48E96792E4DA} + {DCAD7E50-16BA-4E57-B32E-48E96792E4DA} = {77E71695-7E61-4995-863B-5D2278E09EAE} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4ECF116F-0A2D-408B-AF24-681DEE683891} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/CustomFieldHelper.cs b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/CustomFieldHelper.cs new file mode 100644 index 0000000..0663150 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/CustomFieldHelper.cs @@ -0,0 +1,179 @@ +using System.Text.Json; +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Modules.CustomFieldsManager; + +public class CustomFieldHelper : ICustomFieldHelper +{ + private readonly ICustomFieldReferenceObjectRepository _customFieldReferenceObjectRepository; + + public CustomFieldHelper(ICustomFieldReferenceObjectRepository customFieldReferenceObjectRepository) + { + _customFieldReferenceObjectRepository = customFieldReferenceObjectRepository; + } + + public async Task TranslateToCustomFieldDefinitionAsync(CustomField customField, CancellationToken cancellationToken) + { + GeneralIdRef? refElementId = null; + string? parameters = null; + switch (customField.FieldType) + { + case FieldType.Glossary: + var glossaryRef = + await _customFieldReferenceObjectRepository.GetGlossaryReferenceAsync(customField.Id, + cancellationToken); + refElementId = new GeneralIdRef + { + Id = glossaryRef?.GlossaryId + }; + + var glossary = + await _customFieldReferenceObjectRepository.GetGlossaryByGeneralRefIdAsync(refElementId, + cancellationToken); + + refElementId.Guid = glossary?.Guid; + break; + case FieldType.Sequence: + var sequenceRef = + await _customFieldReferenceObjectRepository.GetSequenceReferenceAsync(customField.Id, + cancellationToken); + refElementId = new GeneralIdRef + { + Id = sequenceRef?.SequenceId + }; + + var sequence= + await _customFieldReferenceObjectRepository.GetSequenceByGeneralRefIdAsync(refElementId, + cancellationToken); + + refElementId.Guid = sequence?.Guid; + break; + case FieldType.Number: + var numbersParameters = await _customFieldReferenceObjectRepository.GetNumbersParametersAsync(customField.Id, cancellationToken); + var numbersParams = new NumberFieldParameters + { + MinimumValue = numbersParameters!.MinimumValue?.ToString().TrimEnd('0').TrimEnd('.'), + MaximumValue = numbersParameters!.MaximumValue?.ToString().TrimEnd('0').TrimEnd('.'), + Step = numbersParameters!.Step?.ToString().TrimEnd('0').TrimEnd('.') + }; + parameters = JsonSerializer.Serialize(numbersParams); + break; + case FieldType.Text: + var textsParameters = await _customFieldReferenceObjectRepository.GetTextsParametersAsync(customField.Id, cancellationToken); + var textsParams = new TextFieldParameters + { + MultiLine = textsParameters != null && textsParameters.MultiLine!.Value + }; + parameters = JsonSerializer.Serialize(textsParams); + break; + } + + return new CustomFieldDefinition + { + Id = customField.Id, + Name = customField.Name, + DefaultValue = customField.DefaultValue, + Guid = customField.Guid, + FieldType = customField.FieldType, + MinEntries = customField.MinEntries, + MaxEntries = customField.MaxEntries, + RefElementId = refElementId, + Parameters = parameters + }; + } + + public async Task GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + { + return await _customFieldReferenceObjectRepository.GetFormTemplateByGeneralRefIdAsync(idRef, cancellationToken); + } + + public async Task GetGlossaryByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + { + return await _customFieldReferenceObjectRepository.GetGlossaryByGeneralRefIdAsync(idRef, cancellationToken); + } + + public async Task GetDomainByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + { + return await _customFieldReferenceObjectRepository.GetDomainByGeneralRefIdAsync(idRef, cancellationToken); + } + + public async Task> CustomFieldValuesList( + IEnumerable enumerableCustomFieldValues, + CancellationToken cancellationToken + ) + { + var customFieldValues = new List(); + foreach (var customFieldValue in enumerableCustomFieldValues) + { + var customFieldValueItem = new CustomFieldValue + { + DisplayValue = customFieldValue.DisplayValue + }; + + switch (customFieldValue.CustomField.FieldType) + { + case FieldType.FormTemplate: + var templateRefId = (await GetFormTemplateByGeneralRefIdAsync(new GeneralIdRef + { Guid = Guid.Parse(customFieldValue.Value) }, + cancellationToken + )).ToGeneralIdRef(); + + customFieldValueItem.Value = templateRefId!; + break; + case FieldType.Glossary: + var glossaryRefId = new GeneralIdRef { Guid = Guid.Parse(customFieldValue.Value) }; + var glossaryValue = + await GetGlossaryByGeneralRefIdAsync(glossaryRefId, cancellationToken); + var glossaryItemRefId = glossaryValue.ToGeneralIdRef(); + customFieldValueItem.Value = glossaryItemRefId!; + break; + case FieldType.Domain: + var domainRefId = new GeneralIdRef { Guid = Guid.Parse(customFieldValue.Value) }; + var domainValue = + await GetDomainByGeneralRefIdAsync(domainRefId, cancellationToken); + var domainItemRefId = domainValue.ToGeneralIdRef(); + customFieldValueItem.Value = domainItemRefId!; + break; + default: + customFieldValueItem.Value = customFieldValue.Value; + break; + } + + var customFieldValuesItem = GetOrCreatecustomFieldValueItem(customFieldValues, customFieldValue.CustomField.ToGeneralIdRef()!); + customFieldValuesItem.Values.Add(customFieldValueItem); + } + + return customFieldValues; + } + + private static CustomFieldValues GetOrCreatecustomFieldValueItem( + List customFieldValues, + GeneralIdRef generalIdRef + ) + { + var customFieldValuesItem = customFieldValues.FirstOrDefault(x => x.Id.Equals(generalIdRef)); + + if (customFieldValuesItem == null) + { + customFieldValuesItem = new CustomFieldValues + { + Id = generalIdRef, + Values = [] + }; + + customFieldValues.Add(customFieldValuesItem); + } + + return customFieldValuesItem; + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/CustomFieldManager.cs b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/CustomFieldManager.cs new file mode 100644 index 0000000..9c2b3d4 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/CustomFieldManager.cs @@ -0,0 +1,395 @@ +using System.Linq.Expressions; +using System.Text.Json; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.models.@base; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Utilities.Pagination; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Modules.CustomFieldsManager; + +public class CustomFieldManager : ICustomFieldManager +{ + private enum UpdateType + { + NoReferenceNeeded = 0, + SameObjTypeReference = 1, + DifferentObjectReference = 2 + } + + private readonly ICustomFieldRepository _customFieldRepository; + private readonly ICustomFieldReferenceObjectRepository _customFieldReferenceObjectRepository; + private readonly ICustomFieldHelper _customFieldHelper; + + public CustomFieldManager(ICustomFieldRepository customFieldRepository, ICustomFieldReferenceObjectRepository customFieldReferenceObjectRepository, ICustomFieldHelper customFieldHelper) + { + _customFieldRepository = customFieldRepository; + _customFieldReferenceObjectRepository = customFieldReferenceObjectRepository; + _customFieldHelper = customFieldHelper; + } + + private async Task> ValidateFieldDefinition(FieldType fieldType, IGeneralIdRef? idRef, CancellationToken cancellationToken) + { + if (!ContainsReferenceType(fieldType)) + return (true, null); + + if (idRef == null) + return (false, null); + + return await (fieldType switch + { + FieldType.Sequence => ValidateDelegate(() => + _customFieldReferenceObjectRepository.GetSequenceByGeneralRefIdAsync(idRef, cancellationToken)), + FieldType.Glossary => ValidateDelegate(() => + _customFieldReferenceObjectRepository.GetGlossaryByGeneralRefIdAsync(idRef, cancellationToken)), + _ => throw new ArgumentException("Add field type to the switch!"), + }); + + } + + private static async Task<(bool, long?)> ValidateDelegate(Func> func) where T : IId? + { + return await func() is IId res + ? (true, res!.Id) + : (false, null); + } + + private static bool ContainsReferenceType(FieldType value) + => value is (FieldType.Sequence or FieldType.Glossary); + + private static void Assert(CustomField? customField) + { + AssertExists(customField); + + switch (customField!.FieldType) + { + case FieldType.Sequence: + if (customField.MinEntries != 1) +#pragma warning disable CA2208 // Instantiate argument exceptions correctly + throw new ArgumentException($"Must be 1 for fields of type {customField.FieldType}", paramName: nameof(customField.MinEntries)); + + if (customField.MaxEntries != 1) + throw new ArgumentException($"Must be 1 for fields of type {customField.FieldType}", paramName: nameof(customField.MaxEntries)); +#pragma warning restore CA2208 // Instantiate argument exceptions correctly + break; + } + } + + private static void AssertExists(CustomField? customField) + { + if (customField == null || customField.Deleted) + throw new NotFoundException($"There is no CustomField with this Id"); + } + + private async Task AssertFieldReference(FieldType fieldType, GeneralIdRef? idRef, CancellationToken cancellationToken) + { + var res = await ValidateFieldDefinition(fieldType, idRef, cancellationToken); + if (!res.Item1) + { + throw new InvalidReferenceObjectId($"There is no object of type {fieldType} with the given RefElementId ({idRef?.Id.ToString() ?? idRef?.Guid.ToString()})"); + } + return res.Item2; + } + + private async Task ValidateName(string customFieldName, GeneralIdRef idRef, CancellationToken cancellationToken) + { + var res = await _customFieldRepository.GetByNameAsync(customFieldName, cancellationToken); + if (res != null) + { + if (res.Guid != idRef.Guid || res.Id != idRef.Id) + { + throw new ExistsException($"A Custom field with this name exists {customFieldName}"); + } + return; + } + await ValidateName(customFieldName, cancellationToken); + } + private async Task ValidateName(string customFieldName, CancellationToken cancellationToken) + { + if (await _customFieldRepository.GetByNameAsync(customFieldName, cancellationToken) != null) + { + throw new ExistsException($"A Custom field with this name exists {customFieldName}"); + } + } + + public async Task> GetFieldsAsync(Paging paging, CancellationToken cancellationToken) + { + var sequences = _customFieldRepository.GetCustomFieldList(); + + var paginatedData = await PaginatedData.Paginate(sequences, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(x => new CustomFieldDefinition + { + Id = x.Id, + Guid = x.Guid, + Name = x.Name, + DefaultValue = x.DefaultValue, + FieldType = x.FieldType, + }) + + }; + + return paginatedResult; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "fieldtype" => x => x.FieldType.ToString().Contains(value), + "defaultvalue" => x => x.DefaultValue.ToString().Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "fieldtype" => x => x.FieldType, + "defaultvalue" => x => x.DefaultValue, + _ => x => x.Name + }; + } + + public async Task CreateFieldAsync(AuditUserDetails auditUserDetails, CreateCustomField customField, CancellationToken cancellationToken) + { + await _customFieldRepository.TransactionAsync(async () => + { + await ValidateName(customField.Name, cancellationToken); + + if (customField.Guid != null && await _customFieldRepository.GetByIdAsync(new GeneralIdRef { Guid = customField.Guid }, cancellationToken) != null) + throw new ExistsException("A Field with this id exists"); + + var refId = await AssertFieldReference(customField.FieldType, customField.RefElementId!, cancellationToken); + + var customfFieldReal = new CustomField + { + DefaultValue = customField.DefaultValue, + FieldType = customField.FieldType, + Name = customField.Name, + MaxEntries = customField.MaxEntries, + MinEntries = customField.MinEntries, + Guid = customField.Guid ?? Guid.NewGuid() + }; + + Assert(customfFieldReal); + await _customFieldRepository.CreateAsync(auditUserDetails, customfFieldReal, cancellationToken); + await DealWithParameters(auditUserDetails, customField, null, customfFieldReal, refId, cancellationToken); + }); + } + + public async Task DeleteFieldAsync(AuditUserDetails auditUserDetails, IGeneralIdRef id, CancellationToken cancellationToken) + { + await _customFieldRepository.TransactionAsync(async () => + { + var customField = await _customFieldRepository.GetByIdAsync(id, cancellationToken); + AssertExists(customField); + customField!.Deleted = true; + await _customFieldRepository.EditAsync(auditUserDetails, customField!, cancellationToken); + }); + } + + public async Task EditFieldAsync( + AuditUserDetails auditUserDetails, + EditCustomFields customField, + CancellationToken cancellationToken + ) + { + await _customFieldRepository.TransactionAsync(async () => + { + var customFieldOriginal = await _customFieldRepository.GetByIdAsync(customField.Id, cancellationToken); + Assert(customFieldOriginal); + + var originalFieldType = customFieldOriginal!.FieldType; + var refId = await AssertFieldReference(customField.FieldType, customField.RefElementId!, cancellationToken); + + customFieldOriginal.DefaultValue = customField.DefaultValue; + customFieldOriginal.FieldType = customField.FieldType; + + if (customFieldOriginal.Name != customField.Name) + { + await ValidateName(customField.Name, customField.Id, cancellationToken); + customFieldOriginal.Name = customField.Name; + } + + customFieldOriginal.MaxEntries = customField.MaxEntries; + customFieldOriginal.MinEntries = customField.MinEntries; + + await DealWithParameters(auditUserDetails, customField, originalFieldType, customFieldOriginal, refId, cancellationToken); + + Assert(customFieldOriginal); + await _customFieldRepository.EditAsync(auditUserDetails, customFieldOriginal, cancellationToken); + }); + } + + private async Task DealWithParameters( + AuditUserDetails auditUserDetails, + CustomFieldBase customField, + FieldType? originalFieldType, + CustomField customFieldOriginal, + long? refId, + CancellationToken cancellationToken + ) + { + await FieldDeltaUpdate(FieldType.Glossary, customField, originalFieldType, + async () => await _customFieldReferenceObjectRepository.CreateGlossaryReferenceAsync(auditUserDetails, customFieldOriginal!.Id, refId!.Value, cancellationToken), + async () => { + var customFieldGlossary = await _customFieldReferenceObjectRepository.GetGlossaryReferenceAsync(customFieldOriginal!.Id, cancellationToken); + customFieldGlossary!.GlossaryId = refId!.Value; + await _customFieldReferenceObjectRepository.EditGlossaryReferenceAsync(auditUserDetails, customFieldGlossary, cancellationToken); + }, + async () => await _customFieldReferenceObjectRepository.DeleteGlossaryReferenceAsync(auditUserDetails, customFieldOriginal.Id, cancellationToken) + ); + await FieldDeltaUpdate(FieldType.Sequence, customField, originalFieldType, + async () => await _customFieldReferenceObjectRepository.CreateSequenceReferenceAsync(auditUserDetails, customFieldOriginal.Id, refId!.Value, cancellationToken), + async () => { + var customFieldsequence = await _customFieldReferenceObjectRepository.GetSequenceReferenceAsync(customFieldOriginal!.Id, cancellationToken); + customFieldsequence!.SequenceId = refId!.Value; + await _customFieldReferenceObjectRepository.EditSequenceReferenceAsync(auditUserDetails, customFieldsequence, cancellationToken); + }, + async () => await _customFieldReferenceObjectRepository.DeleteSequenceReferenceAsync(auditUserDetails, customFieldOriginal.Id, cancellationToken) + ); + await FieldDeltaUpdate(FieldType.Text, customField, originalFieldType, + async () => + { + var textFieldParameters = DeserializeParameters(customField); + var customFieldText = new CustomFieldText + { + CustomFieldId = customFieldOriginal.Id + }; + SetCustomFieldTextParameters(textFieldParameters, customFieldText); + + await _customFieldReferenceObjectRepository.CreateCustomFieldTextsAsync(auditUserDetails, customFieldText, cancellationToken); + }, + async () => { + var textFieldParameters = DeserializeParameters(customField); + var customFieldText = await GetCustomFieldText(customFieldOriginal, cancellationToken); + SetCustomFieldTextParameters(textFieldParameters, customFieldText); + + await _customFieldReferenceObjectRepository.EditCustomFieldTextsAsync(auditUserDetails, customFieldText, textFieldParameters, cancellationToken); + }, + async () => + { + var customFieldText = await GetCustomFieldText(customFieldOriginal, cancellationToken); + + await _customFieldReferenceObjectRepository.DeleteCustomFieldTextsAsync(auditUserDetails, customFieldText, cancellationToken); + } + ); + await FieldDeltaUpdate(FieldType.Number, customField, originalFieldType, + async () => + { + var numberFieldParameters = DeserializeParameters(customField); + var customFieldNumber = new CustomFieldNumber + { + CustomFieldId = customFieldOriginal.Id + }; + SetCustomFieldNumberParameters(numberFieldParameters, customFieldNumber); + + await _customFieldReferenceObjectRepository.CreateCustomFieldNumbersAsync(auditUserDetails, customFieldNumber, cancellationToken); + }, + async () => { + var numberFieldParameters = DeserializeParameters(customField); + var customFieldNumber = await GetCustomFieldNumber(customFieldOriginal, cancellationToken); + SetCustomFieldNumberParameters(numberFieldParameters, customFieldNumber); + + await _customFieldReferenceObjectRepository.EditCustomFieldNumbersAsync(auditUserDetails, customFieldNumber, numberFieldParameters, cancellationToken); + }, + async () => + { + var customFieldNumber = await GetCustomFieldNumber(customFieldOriginal, cancellationToken); + + await _customFieldReferenceObjectRepository.DeleteCustomFieldNumbersAsync(auditUserDetails, customFieldNumber, cancellationToken); + }); + } + + private async Task GetCustomFieldNumber(CustomField customFieldOriginal, CancellationToken cancellationToken) + { + var customFieldNumber = + await _customFieldReferenceObjectRepository.GetNumbersParametersAsync(customFieldOriginal.Id, + cancellationToken) ?? throw new NullReferenceException("unable to find existing custom field number"); + return customFieldNumber; + } + + private async Task GetCustomFieldText(CustomField customFieldOriginal, CancellationToken cancellationToken) + { + var customFieldText = + await _customFieldReferenceObjectRepository.GetTextsParametersAsync(customFieldOriginal.Id, + cancellationToken) ?? new CustomFieldText + { + CustomFieldId = customFieldOriginal.Id, + MultiLine = false, + CustomField = customFieldOriginal + }; + return customFieldText; + } + + private static void SetCustomFieldNumberParameters(NumberFieldParameters numberFieldParameters, CustomFieldNumber customFieldNumber) + { + customFieldNumber.MinimumValue = string.IsNullOrWhiteSpace(numberFieldParameters.MinimumValue) ? null : decimal.Parse(numberFieldParameters.MinimumValue); + customFieldNumber.MaximumValue = string.IsNullOrWhiteSpace(numberFieldParameters.MaximumValue) ? null : decimal.Parse(numberFieldParameters.MaximumValue); + customFieldNumber.Step = string.IsNullOrWhiteSpace(numberFieldParameters.Step) ? null : decimal.Parse(numberFieldParameters.Step); + } + + private static void SetCustomFieldTextParameters(TextFieldParameters textFieldParameters, CustomFieldText customFieldText) + { + customFieldText.MultiLine = textFieldParameters.MultiLine; + } + + private static T DeserializeParameters(CustomFieldBase customField) + { + if (string.IsNullOrWhiteSpace(customField.Parameters)) + throw new NullReferenceException($"Parameters must be supplied for {customField.FieldType} fields"); + + var numberFieldParameters = JsonSerializer.Deserialize(customField.Parameters) ?? + throw new ArgumentException($"Parameters not correctly formatted for {customField.FieldType} field"); + return numberFieldParameters; + } + + private static async Task FieldDeltaUpdate(FieldType fieldType, CustomFieldBase customField, FieldType? originalFieldType, Func add, Func edit, Func delete) + { + var originalIfFieldType = originalFieldType == fieldType; + var newIfFieldType = customField.FieldType == fieldType; + if (originalIfFieldType && newIfFieldType) + await edit(); + else if (originalIfFieldType && !newIfFieldType) + await delete(); + else if (!originalIfFieldType && newIfFieldType) + await add(); + } + + + public async Task GetFieldAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + var customField = await _customFieldRepository.GetByIdAsync(id, cancellationToken); + Assert(customField); + return await _customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField!, cancellationToken); + } + + public async Task GetFieldAsync(string name, CancellationToken cancellationToken) + { + var customField = await _customFieldRepository.GetByNameAsync(name, cancellationToken); + if (customField == null || customField.Deleted) + { + throw new NotFoundException($"There is no CustomField with this name: {name}"); + } + + return await _customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField, cancellationToken); + } +} diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/GlobalSuppressions.cs b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/IocRegistration.cs b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/IocRegistration.cs new file mode 100644 index 0000000..f01ffcc --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/IocRegistration.cs @@ -0,0 +1,19 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.CustomFieldsManager.Repository; + +namespace e_suite.Modules.CustomFieldsManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/Repository/CustomFieldReferenceObjectRepository.cs b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/Repository/CustomFieldReferenceObjectRepository.cs new file mode 100644 index 0000000..dc96c6d --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/Repository/CustomFieldReferenceObjectRepository.cs @@ -0,0 +1,197 @@ +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using Sequence = e_suite.Database.Core.Tables.Sequences.Sequence; + +namespace e_suite.Modules.CustomFieldsManager.Repository; + +public class CustomFieldReferenceObjectRepository : RepositoryBase, ICustomFieldReferenceObjectRepository +{ +#pragma warning disable IDE0290 + public CustomFieldReferenceObjectRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } +#pragma warning restore IDE0290 + + public async Task GetSequenceByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + => await DatabaseDbContext.Sequences.FindByGeneralIdRefAsync(idRef, cancellationToken); + + public async Task GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + => await DatabaseDbContext.FormTemplates.FindByGeneralIdRefAsync(idRef, cancellationToken); + + public async Task GetGlossaryByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + => await DatabaseDbContext.Glossaries.FindByGeneralIdRefAsync(idRef, cancellationToken); + + public async Task GetDomainByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + => await DatabaseDbContext.Domains.FindByGeneralIdRefAsync(idRef, cancellationToken); + + public async Task CreateFormReferenceAsync(AuditUserDetails auditUserDetails, long customField, long formId, CancellationToken cancellationToken) + { + var customFieldSequence = new CustomFieldSequence + { + CustomFieldId = customField, + SequenceId = formId + }; + await DatabaseDbContext.CustomFieldSequences.AddAsync(customFieldSequence, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task CreateGlossaryReferenceAsync(AuditUserDetails auditUserDetails, long customField, long glossaryId, CancellationToken cancellationToken) + { + var customFieldGlossary = new CustomFieldGlossary + { + CustomFieldId = customField, + GlossaryId = glossaryId, + }; + await DatabaseDbContext.CustomFieldGlossaries.AddAsync(customFieldGlossary, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public Task CreateDomainReferenceAsync(AuditUserDetails auditUserDetails, long customField, long formId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public async Task CreateSequenceReferenceAsync(AuditUserDetails auditUserDetails, long customField, long sequenceId, CancellationToken cancellationToken) + { + var customFieldsequence = new CustomFieldSequence + { + CustomFieldId = customField, + SequenceId = sequenceId + }; + await DatabaseDbContext.CustomFieldSequences.AddAsync(customFieldsequence, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteFormReferenceAsync(AuditUserDetails auditUserDetails, long cusotmFieldId, CancellationToken cancellationToken) + { + var refObj = await DatabaseDbContext.CustomFieldFormTemplate.FirstOrDefaultAsync(cf => cf.CustomFieldId == cusotmFieldId, cancellationToken); + if (refObj is not null) + { + DatabaseDbContext.CustomFieldFormTemplate.Remove(refObj); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + } + + public async Task DeleteGlossaryReferenceAsync(AuditUserDetails auditUserDetails, long customFieldId, CancellationToken cancellationToken) + { + var refObj = await DatabaseDbContext.CustomFieldGlossaries.FirstOrDefaultAsync(cf => cf.CustomFieldId == customFieldId, cancellationToken); + if (refObj is not null) + { + DatabaseDbContext.CustomFieldGlossaries.Remove(refObj!); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + } + + public Task DeleteDomainReferenceAsync(AuditUserDetails auditUserDetails, long customField, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public async Task DeleteSequenceReferenceAsync(AuditUserDetails auditUserDetails, long customFieldId, CancellationToken cancellationToken) + { + var refObj = await DatabaseDbContext.CustomFieldSequences.FirstOrDefaultAsync(cf => cf.CustomFieldId == customFieldId, cancellationToken); + if (refObj is not null) + { + DatabaseDbContext.CustomFieldSequences.Remove(refObj!); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + } + + public async Task GetFormReferenceAsync(long customFieldId, CancellationToken cancellationToken) + => await DatabaseDbContext.CustomFieldFormTemplate.FirstOrDefaultAsync(cf => cf.CustomFieldId == customFieldId, cancellationToken); + + public async Task GetSequenceReferenceAsync(long customFieldId, CancellationToken cancellationToken) + => await DatabaseDbContext.CustomFieldSequences.FirstOrDefaultAsync(cf => cf.CustomFieldId == customFieldId, cancellationToken); + + public async Task GetGlossaryReferenceAsync(long customFieldId, CancellationToken cancellationToken) + => await DatabaseDbContext.CustomFieldGlossaries.FirstOrDefaultAsync(cf => cf.CustomFieldId == customFieldId, cancellationToken); + + public async Task CreateCustomFieldNumbersAsync( + AuditUserDetails auditUserDetails, + CustomFieldNumber customFieldNumber, + CancellationToken cancellationToken + ) + { + await DatabaseDbContext.CustomFieldNumber.AddAsync(customFieldNumber, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditCustomFieldNumbersAsync( + AuditUserDetails auditUserDetails, + CustomFieldNumber customFieldNumber, + NumberFieldParameters numberFieldParameters, + CancellationToken cancellationToken + ) + { + DatabaseDbContext.CustomFieldNumber.Update(customFieldNumber); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetNumbersParametersAsync(long customFieldId, CancellationToken cancellationToken) + { + return await DatabaseDbContext.CustomFieldNumber.Where(x => x.CustomFieldId == customFieldId) + .SingleOrDefaultAsync(cancellationToken); + } + + public async Task DeleteCustomFieldNumbersAsync(AuditUserDetails auditUserDetails, CustomFieldNumber customFieldNumber, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFieldNumber.Remove(customFieldNumber!); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditFormReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldFormTemplate customFieldFormTemplate, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFieldFormTemplate.Update(customFieldFormTemplate); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditGlossaryReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldGlossary customFieldGlossary, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFieldGlossaries.Update(customFieldGlossary); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public Task EditDomainReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldGlossary customFieldGlossary, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public async Task EditSequenceReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldSequence customFieldSequence, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFieldSequences.Update(customFieldSequence); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetTextsParametersAsync(long customFieldId, CancellationToken cancellationToken) + { + return await DatabaseDbContext.CustomFieldText.Where(x => x.CustomFieldId == customFieldId) + .SingleOrDefaultAsync(cancellationToken); + } + + public async Task CreateCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, CancellationToken cancellationToken) + { + await DatabaseDbContext.CustomFieldText.AddAsync(customFieldText, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, TextFieldParameters textFieldParameters, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFieldText.Update(customFieldText); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFieldText.Remove(customFieldText!); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/Repository/CustomFieldRepository.cs b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/Repository/CustomFieldRepository.cs new file mode 100644 index 0000000..fd9c1ef --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/Repository/CustomFieldRepository.cs @@ -0,0 +1,46 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.CustomFields; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.CustomFieldsManager.Repository; + +public class CustomFieldRepository : RepositoryBase, ICustomFieldRepository +{ +#pragma warning disable IDE0290 + public CustomFieldRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } +#pragma warning restore IDE0290 + + public async Task CreateAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + await DatabaseDbContext.CustomFields.AddAsync(customField, cancellationToken); + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public IQueryable GetCustomFieldList() + { + return DatabaseDbContext.CustomFields.Where(x => !x.Deleted); + } + + public async Task GetByIdAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + var res = await DatabaseDbContext.CustomFields.FindByGeneralIdRefAsync(id, cancellationToken); + return res; + } + + public async Task GetByNameAsync(string name, CancellationToken cancellationToken) + => await DatabaseDbContext.CustomFields.FirstOrDefaultAsync(cf => cf.Name == name && cf.Deleted == false, cancellationToken); + + + public async Task EditAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + DatabaseDbContext.CustomFields.Update(customField); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} diff --git a/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.csproj b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.csproj new file mode 100644 index 0000000..0b628c9 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager/e-suite.Modules.CustomFieldsManager.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + e_suite.Modules.CustomFieldsManager + enable + enable + + + + + + + + + + + diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/CustomFieldValuesListUnitTests.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/CustomFieldValuesListUnitTests.cs new file mode 100644 index 0000000..45bd5ed --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/CustomFieldValuesListUnitTests.cs @@ -0,0 +1,370 @@ +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.CustomFields; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldHelperUnitTests; + +[TestFixture] +public class CustomFieldValuesListUnitTests : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task CustomFieldValuesList_WhenTranslatingSimpleField_ValuesTransferCorrectly() + { + //Arrange + var customField = new CustomField + { + Id = 999, + Guid = new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"), + FieldType = FieldType.Text, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty + }; + + var customFieldValues = new List + { + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = "Display Test", + Value = "Test", + Index = 0 + } + }; + + //Act + var result = await _customFieldHelper.CustomFieldValuesList(customFieldValues, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Id.Id, Is.EqualTo(999)); + Assert.That(result[0].Id.Guid, Is.EqualTo(new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"))); + Assert.That(result[0].Values, Has.Count.EqualTo(1)); + Assert.That(result[0].Values[0].Value, Is.EqualTo("Test")); + Assert.That(result[0].Values[0].DisplayValue, Is.EqualTo("Display Test")); + }); + } + + [Test] + public async Task CustomFieldValuesList_WhenTranslatingGlossaryField_ValuesTransferCorrectly() + { + //Arrange + var customField = new CustomField + { + Id = 999, + Guid = new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"), + FieldType = FieldType.Glossary, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty + }; + + _fakeCustomFieldReferenceRepository.Glossaries.Add(new Glossary + { + Id = 83, + Guid = new Guid("2781d151-e0cb-4f6a-b2d9-e0b82b6713a6"), + Name = "This is a GlossaryItem" + }); + + var customFieldValues = new List + { + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = "This is a GlossaryItem", + Value = "2781d151-e0cb-4f6a-b2d9-e0b82b6713a6", + Index = 0 + } + }; + + //Act + var result = await _customFieldHelper.CustomFieldValuesList(customFieldValues, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Id.Id, Is.EqualTo(999)); + Assert.That(result[0].Id.Guid, Is.EqualTo(new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"))); + Assert.That(result[0].Values, Has.Count.EqualTo(1)); + Assert.That(result[0].Values[0].Value, Is.Not.Null); + Assert.That(result[0].Values[0].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Id, Is.EqualTo(83)); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Guid, Is.EqualTo(new Guid("2781d151-e0cb-4f6a-b2d9-e0b82b6713a6"))); + Assert.That(result[0].Values[0].DisplayValue, Is.EqualTo("This is a GlossaryItem")); + }); + } + + [Test] + public async Task CustomFieldValuesList_WhenTranslatingGlossaryFieldWithMultipleValues_ValuesTransferCorrectly() + { + //Arrange + var customField = new CustomField + { + Id = 999, + Guid = new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"), + FieldType = FieldType.Glossary, + MinEntries = 1, + MaxEntries = null, + DefaultValue = string.Empty + }; + + _fakeCustomFieldReferenceRepository.Glossaries.Add(new Glossary + { + Id = 83, + Guid = new Guid("2781d151-e0cb-4f6a-b2d9-e0b82b6713a6"), + Name = "This is a GlossaryItem" + }); + + _fakeCustomFieldReferenceRepository.Glossaries.Add(new Glossary + { + Id = 84, + Guid = new Guid("B22C0DA9-280B-4CC8-AA55-C88BAAE18D66"), + Name = "Item 2" + }); + + + var customFieldValues = new List + { + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = "This is a GlossaryItem", + Value = "2781d151-e0cb-4f6a-b2d9-e0b82b6713a6", + Index = 0 + }, + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = "Item 2", + Value = "B22C0DA9-280B-4CC8-AA55-C88BAAE18D66", + Index = 1 + } + }; + + //Act + var result = await _customFieldHelper.CustomFieldValuesList(customFieldValues, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Id.Id, Is.EqualTo(999)); + Assert.That(result[0].Id.Guid, Is.EqualTo(new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"))); + + + Assert.That(result[0].Values, Has.Count.EqualTo(2)); + + Assert.That(result[0].Values[0].Value, Is.Not.Null); + Assert.That(result[0].Values[0].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Id, Is.EqualTo(83)); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Guid, Is.EqualTo(new Guid("2781d151-e0cb-4f6a-b2d9-e0b82b6713a6"))); + Assert.That(result[0].Values[0].DisplayValue, Is.EqualTo("This is a GlossaryItem")); + + Assert.That(result[0].Values[1].Value, Is.Not.Null); + Assert.That(result[0].Values[1].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[1].Value)).Id, Is.EqualTo(84)); + Assert.That(((GeneralIdRef)(result[0].Values[1].Value)).Guid, Is.EqualTo(new Guid("B22C0DA9-280B-4CC8-AA55-C88BAAE18D66"))); + Assert.That(result[0].Values[1].DisplayValue, Is.EqualTo("Item 2")); + + }); + } + + [Test] + public async Task CustomFieldValuesList_WhenTranslatingDomainField_ValuesTransferCorrectly() + { + //Arrange + var customField = new CustomField + { + Id = 999, + Guid = new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"), + FieldType = FieldType.Domain, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty + }; + + _fakeCustomFieldReferenceRepository.Domains.Add(new Domain + { + Id = 13, + Guid = new Guid("5ffcf209-15c6-4924-8570-6415a639c4a4"), + Name = "Test Domain" + }); + + var customFieldValues = new List + { + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = "DomainItem", + Value = "5ffcf209-15c6-4924-8570-6415a639c4a4", + Index = 0 + } + }; + + //Act + var result = await _customFieldHelper.CustomFieldValuesList(customFieldValues, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Id.Id, Is.EqualTo(999)); + Assert.That(result[0].Id.Guid, Is.EqualTo(new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"))); + Assert.That(result[0].Values, Has.Count.EqualTo(1)); + Assert.That(result[0].Values[0].Value, Is.Not.Null); + Assert.That(result[0].Values[0].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Id, Is.EqualTo(13)); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Guid, Is.EqualTo(new Guid("5ffcf209-15c6-4924-8570-6415a639c4a4"))); + Assert.That(result[0].Values[0].DisplayValue, Is.EqualTo("DomainItem")); + }); + } + + [Test] + public async Task CustomFieldValuesList_WhenTranslatingDomainFieldWithMultipleValues_ValuesTransferCorrectly() + { + //Arrange + var customField = new CustomField + { + Id = 999, + Guid = new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"), + FieldType = FieldType.Domain, + MinEntries = 1, + MaxEntries = null, + DefaultValue = string.Empty + }; + + var domainOneGuid = "9dc6f024-c02c-4674-8e33-362f636f8ce4"; + var domainTwoGuid = "a9890395-8782-4b3e-878b-efdb8fba3c12"; + var domainOneName = "Domain One"; + var domainTwoName = "Domain Two"; + + _fakeCustomFieldReferenceRepository.Domains.Add(new Domain + { + Id = 83, + Guid = new Guid(domainOneGuid), + Name = domainOneName + }); + + _fakeCustomFieldReferenceRepository.Domains.Add(new Domain + { + Id = 84, + Guid = new Guid(domainTwoGuid), + Name = domainTwoName + }); + + var customFieldValues = new List + { + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = domainOneName, + Value = domainOneGuid, + Index = 0 + }, + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = domainTwoName, + Value = domainTwoGuid, + Index = 1 + } + }; + + //Act + var result = await _customFieldHelper.CustomFieldValuesList(customFieldValues, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Id.Id, Is.EqualTo(999)); + Assert.That(result[0].Id.Guid, Is.EqualTo(new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"))); + + Assert.That(result[0].Values, Has.Count.EqualTo(2)); + + Assert.That(result[0].Values[0].Value, Is.Not.Null); + Assert.That(result[0].Values[0].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Id, Is.EqualTo(83)); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Guid, Is.EqualTo(new Guid(domainOneGuid))); + Assert.That(result[0].Values[0].DisplayValue, Is.EqualTo(domainOneName)); + + Assert.That(result[0].Values[1].Value, Is.Not.Null); + Assert.That(result[0].Values[1].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[1].Value)).Id, Is.EqualTo(84)); + Assert.That(((GeneralIdRef)(result[0].Values[1].Value)).Guid, Is.EqualTo(new Guid(domainTwoGuid))); + Assert.That(result[0].Values[1].DisplayValue, Is.EqualTo(domainTwoName)); + }); + } + + [Test] + public async Task CustomFieldValuesList_WhenTranslatingTemplateField_ValuesTransferCorrectly() + { + //Arrange + var customField = new CustomField + { + Id = 999, + Guid = new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"), + FieldType = FieldType.FormTemplate, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty + }; + + _fakeCustomFieldReferenceRepository.FormTemplates.Add(new FormTemplate() + { + Id = 76, + Guid = new Guid("74c51c57-e23e-4d0a-ad7d-273acc6883ce"), + Name = "My Test Form Template" + }); + + var customFieldValues = new List + { + new FormFieldInstance + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = "My Test Form Template", + Value = "74c51c57-e23e-4d0a-ad7d-273acc6883ce", + Index = 0 + } + }; + + //Act + var result = await _customFieldHelper.CustomFieldValuesList(customFieldValues, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Id.Id, Is.EqualTo(999)); + Assert.That(result[0].Id.Guid, Is.EqualTo(new Guid("dca50da4-03d6-438e-bf90-c2ef11f455d8"))); + Assert.That(result[0].Values, Has.Count.EqualTo(1)); + Assert.That(result[0].Values[0].Value, Is.Not.Null); + Assert.That(result[0].Values[0].Value, Is.AssignableTo(typeof(GeneralIdRef))); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Id, Is.EqualTo(76)); + Assert.That(((GeneralIdRef)(result[0].Values[0].Value)).Guid, Is.EqualTo(new Guid("74c51c57-e23e-4d0a-ad7d-273acc6883ce"))); + Assert.That(result[0].Values[0].DisplayValue, Is.EqualTo("My Test Form Template")); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/GetFormTemplateByGeneralRefIdAsyncUnitTests.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/GetFormTemplateByGeneralRefIdAsyncUnitTests.cs new file mode 100644 index 0000000..a78b864 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/GetFormTemplateByGeneralRefIdAsyncUnitTests.cs @@ -0,0 +1,46 @@ +using e_suite.Database.Core.Tables.Forms; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldHelperUnitTests; + +[TestFixture] +public class GetFormTemplateByGeneralRefIdAsyncUnitTests : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task GetFormTemplateByGeneralRefIdAsync_WhenGeneralRefIdDoesNotExist_ReturnsNull() + { + //Arrange + var idRef = new GeneralIdRef(); + + //Act + var result = await _customFieldHelper.GetFormTemplateByGeneralRefIdAsync(idRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Null); + } + + + [Test] + public async Task GetFormTemplateByGeneralRefIdAsync_WhenGeneralRefIdExists_ReturnsExpectedValue() + { + //Arrange + var idRef = new GeneralIdRef + { + Id = 72 + }; + + _fakeCustomFieldReferenceRepository.FormTemplates.Add( new FormTemplate() + { + Id = 72 + }); + + //Act + var result = await _customFieldHelper.GetFormTemplateByGeneralRefIdAsync(idRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result!.Id, Is.EqualTo(72)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/GetGlossaryByGeneralRefIdAsyncUnitTests.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/GetGlossaryByGeneralRefIdAsyncUnitTests.cs new file mode 100644 index 0000000..55d9a45 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/GetGlossaryByGeneralRefIdAsyncUnitTests.cs @@ -0,0 +1,47 @@ +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldHelperUnitTests; + +[TestFixture] +public class GetGlossaryByGeneralRefIdAsyncUnitTests : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task GetFormTemplateByGeneralRefIdAsync_WhenGeneralRefIdDoesNotExist_ReturnsNull() + { + //Arrange + var idRef = new GeneralIdRef(); + + //Act + var result = await _customFieldHelper.GetGlossaryByGeneralRefIdAsync(idRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Null); + } + + + [Test] + public async Task GetFormTemplateByGeneralRefIdAsync_WhenGeneralRefIdExists_ReturnsExpectedValue() + { + //Arrange + var idRef = new GeneralIdRef + { + Id = 83 + }; + + _fakeCustomFieldReferenceRepository.Glossaries.Add(new Glossary() + { + Id = 83 + }); + + //Act + var result = await _customFieldHelper.GetGlossaryByGeneralRefIdAsync(idRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result!.Id, Is.EqualTo(83)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/TranslateToCustomFieldDefinitionAsyncUnitTests.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/TranslateToCustomFieldDefinitionAsyncUnitTests.cs new file mode 100644 index 0000000..28feb24 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldHelperUnitTests/TranslateToCustomFieldDefinitionAsyncUnitTests.cs @@ -0,0 +1,154 @@ +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.Database.Core.Tables.Sequences; +using eSuite.Core.CustomFields; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldHelperUnitTests; + +[TestFixture] +public class TranslateToCustomFieldDefinitionAsyncUnitTests : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task TranslateToCustomFieldDefinitionAsync_FieldTypeGlossary_ReturnsCorrectInformation() + { + //Arrange + var customField = new CustomField + { + FieldType = FieldType.Glossary, + Id = 42, + Guid = new Guid("1dda3a6f-24cf-4904-9dbe-1394457e871c"), + Name = "TestField", + MinEntries = 0, + MaxEntries = 1 + }; + + var glossaryItem = new Glossary + { + Id = 34, + Guid = new Guid("a4e32489-42be-4e71-9198-4740e01e1e56") + }; + + _fakeCustomFieldReferenceRepository.CustomFieldGlossaries.Add(new CustomFieldGlossary + { + CustomField = customField, + CustomFieldId = customField.Id, + Glossary = glossaryItem, + GlossaryId = glossaryItem.Id, + } + ); + + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossaryItem); + + //Act + var result = await _customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result.FieldType, Is.EqualTo(FieldType.Glossary)); + Assert.That(result.Id, Is.EqualTo(42)); + Assert.That(result.Guid, Is.EqualTo(new Guid("1dda3a6f-24cf-4904-9dbe-1394457e871c"))); + Assert.That(result.Name, Is.EqualTo("TestField")); + Assert.That(result.MinEntries, Is.EqualTo(0)); + Assert.That(result.MaxEntries, Is.EqualTo(1)); + Assert.That(result.RefElementId, Is.Not.Null); + Assert.That(result.RefElementId!.Id, Is.EqualTo(34)); + Assert.That(result.RefElementId!.Guid, Is.EqualTo(new Guid("a4e32489-42be-4e71-9198-4740e01e1e56"))); + }); + } + + [Test] + public async Task TranslateToCustomFieldDefinitionAsync_FieldTypeSequence_ReturnsCorrectInformation() + { + //Arrange + var customField = new CustomField + { + FieldType = FieldType.Sequence, + Id = 83, + Guid = new Guid("8d8b56f6-df96-4f9a-b94f-51a45d14f5af"), + Name = "TestSequenceField", + MinEntries = 0, + MaxEntries = 1 + }; + + var sequenceItem = new Sequence + { + Id = 69, + Guid = new Guid("73ffc36c-6479-4f6e-afa7-4d65f35d8d20") + }; + + _fakeCustomFieldReferenceRepository.CustomFieldSequences.Add(new CustomFieldSequence + { + CustomField = customField, + CustomFieldId = customField.Id, + Sequence = sequenceItem, + SequenceId = sequenceItem.Id, + } + ); + + _fakeCustomFieldReferenceRepository.Sequences.Add(sequenceItem); + + //Act + var result = await _customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result.FieldType, Is.EqualTo(FieldType.Sequence)); + Assert.That(result.Id, Is.EqualTo(83)); + Assert.That(result.Guid, Is.EqualTo(new Guid("8d8b56f6-df96-4f9a-b94f-51a45d14f5af"))); + Assert.That(result.Name, Is.EqualTo("TestSequenceField")); + Assert.That(result.MinEntries, Is.EqualTo(0)); + Assert.That(result.MaxEntries, Is.EqualTo(1)); + Assert.That(result.RefElementId, Is.Not.Null); + Assert.That(result.RefElementId!.Id, Is.EqualTo(69)); + Assert.That(result.RefElementId!.Guid, Is.EqualTo(new Guid("73ffc36c-6479-4f6e-afa7-4d65f35d8d20"))); + }); + } + + + [Test] + public async Task TranslateToCustomFieldDefinitionAsync_FieldTypeNumber_ReturnsCorrectInformation() + { + //Arrange + var customField = new CustomField + { + FieldType = FieldType.Number, + Id = 83, + Guid = new Guid("f0175809-0b4e-4fe2-8fd1-c2bd9949b546"), + Name = "TestNumberField", + MinEntries = 0, + MaxEntries = 1 + }; + + _fakeCustomFieldReferenceRepository.CustomFieldNumber.Add( new CustomFieldNumber + { + CustomFieldId = customField.Id, + CustomField = customField, + MinimumValue = 10, + MaximumValue = 100, + Step = 5 + }); + + //Act + var result = await _customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result.FieldType, Is.EqualTo(FieldType.Number)); + Assert.That(result.Id, Is.EqualTo(83)); + Assert.That(result.Guid, Is.EqualTo(customField.Guid)); + Assert.That(result.Name, Is.EqualTo(customField.Name)); + Assert.That(result.MinEntries, Is.EqualTo(0)); + Assert.That(result.MaxEntries, Is.EqualTo(1)); + Assert.That(result.RefElementId, Is.Null); + Assert.That(result.Parameters, Is.EqualTo("{\"minValue\":\"1\",\"maxValue\":\"1\",\"step\":\"5\"}")); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/CreateCustomFieldUnitTest.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/CreateCustomFieldUnitTest.cs new file mode 100644 index 0000000..5d4af57 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/CreateCustomFieldUnitTest.cs @@ -0,0 +1,468 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.CustomFields; +using Sequence = e_suite.Database.Core.Tables.Sequences.Sequence; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldManagerUnitTests; + +public class CreateCustomFieldUnitTest : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task CreateCustomField_AutoGenId_SaveChangesId() + { + + //Arrange + var customFieldDto = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test", + Guid = null, + MinEntries = 5, + MaxEntries = 5, + Parameters = "{\"multiLine\":false}" + }; + _customFieldManager = new CustomFieldManager(_fakeCustomFieldRepository!, _fakeCustomFieldReferenceRepository, _customFieldHelper); + _customFieldRepository.Setup(x => x.CreateAsync(It.IsAny(), It.Is(x => x.Name == "Test"), It.IsAny())); + + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customFieldDto, default); + + //Assert; + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldRepository!.CustomFields, Has.Count.EqualTo(1)); + Assert.That(_fakeCustomFieldRepository!.CustomFields[0].MaxEntries, Is.EqualTo(5)); + Assert.That(_fakeCustomFieldRepository!.CustomFields[0].MinEntries, Is.EqualTo(5)); + Assert.That(_fakeCustomFieldRepository!.CustomFields[0].Name, Is.EqualTo("Test")); + Assert.That(_fakeCustomFieldRepository!.CustomFields[0].DefaultValue, Is.EqualTo("1")); + }); + } + + [Test] + public async Task CreateCustomField_WithSameName_ThrowsException() + { + //Arrange + var guid = new Guid("4aef2005-f7c2-4b9b-bf0c-cd04eab6564c"); + var guidSecond = new Guid("6a94e1b7-5cf7-4441-a2a0-707727a14048"); + _fakeCustomFieldRepository = new FakeCustomFieldRepository(); + var customFieldDto = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test", + Guid = guid, + Parameters = "{\"multiLine\":false}" + }; + var customFieldDtoSecond = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test", + Guid = guidSecond, + Parameters = "{\"multiLine\":false}" + }; + + await _customFieldManager.CreateFieldAsync(auditResult, customFieldDto, default); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customFieldDtoSecond, default); + }); + } + + [Test] + public async Task CreateCustomField_WithPredefinedGuidId_SaveChanges() + { + //Arrange + var guid = new Guid("85ccdb80-912a-4de1-8961-746990e1031b"); + var guidSecond = new Guid("4af24c5c-5bc0-4fa9-aea9-ab5c73e52364"); + + var customFieldDto = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test", + Guid = guid, + MinEntries = 10, + MaxEntries = 10, + Parameters = "{\"multiLine\":false}" + }; + var customFieldDtoSecond = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test2", + Guid = guidSecond, + MinEntries = 11, + MaxEntries = 11, + Parameters = "{\"multiLine\":false}" + }; + + await _customFieldManager.CreateFieldAsync(auditResult, customFieldDto, default); + + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customFieldDtoSecond, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldRepository.CustomFields.Any(x => x.Guid == guid)); + Assert.That(_fakeCustomFieldRepository.CustomFields.Any(x => x.Guid == guidSecond)); + Assert.That(_fakeCustomFieldRepository.CustomFields[0].MinEntries, Is.EqualTo(10)); + Assert.That(_fakeCustomFieldRepository.CustomFields[0].MaxEntries, Is.EqualTo(10)); + Assert.That(_fakeCustomFieldRepository.CustomFields[1].MaxEntries, Is.EqualTo(11)); + Assert.That(_fakeCustomFieldRepository.CustomFields[1].MaxEntries, Is.EqualTo(11)); + }); + } + + [Test] + public async Task CreateCustomField_WithSameGuids_ThrowsException() + { + //Arrange + var guid = new Guid("55b2a79b-c007-48ef-a85f-092d9f5db952"); + _fakeCustomFieldRepository = new FakeCustomFieldRepository(); + + var customFieldDto = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test", + Guid = guid, + Parameters = "{\"multiLine\":false}" + }; + var customFieldDtoSecond = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Text, + Name = "Test2", + Guid = guid, + Parameters = "{\"multiLine\":false}" + }; + + await _customFieldManager.CreateFieldAsync(auditResult, customFieldDto, default); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await _customFieldManager.CreateFieldAsync(new AuditUserDetails(), customFieldDtoSecond, default); + }); + } + + [Test] + public async Task CreateCustomField_WithFieldTypeGlossaryWithOnlyIdForRefObj_SaveChanges() + { + //Arrange + var glossary = new Glossary + { + Id = 1, + Deleted = false, + Guid = new Guid("50551979-ceff-4a1e-897d-7abb6d786ea8"), + Name = "Form Name" + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + var customField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Glossary, + RefElementId = new GeneralIdRef + { + Guid = null, + Id = 1 + }, + Guid = null, + Name = "FormGuid", + }; + + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customField, default); + + //Assert + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(1)); + } + + [Test] + public async Task CreateCustomField_WithFieldTypeSequenceWithOnlyIdForRefObj_SaveChanges() + { + //Arrange + var sequence = new Sequence + { + Id = 1, + Deleted = false, + Guid = new Guid("1db9c5f7-3ee8-4516-8b27-8c8047c8e04b"), + Name = "Form Name" + }; + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + var customField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Sequence, + RefElementId = new GeneralIdRef + { + Guid = null, + Id = 1 + }, + Guid = null, + Name = "FormGuid", + MaxEntries = 1, + MinEntries = 1, + }; + + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customField, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences, Has.Count.EqualTo(1)); + Assert.That(customField.MaxEntries, Is.EqualTo(1)); + Assert.That(customField.MinEntries, Is.EqualTo(1)); + }); + } + + [Test] + public async Task CreateCustomField_WithFieldTypeSequenceWithRefIdOnlyGuidAutogenForTheCustomField_SaveChanges() + { + //Arrange + var sequenceGuid = new Guid("9e22c2e5-b897-47af-b14a-d2b5903fb609"); + var audit = new AuditUserDetails(); + var createCustomField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Sequence, + RefElementId = new GeneralIdRef + { + Guid = sequenceGuid, + }, + + Guid = null, + Name = "FormGuid", + MaxEntries = 1, + MinEntries = 1 + }; + var sequence = new Sequence + { + Id = 1, + Guid = sequenceGuid, + Name = "Test", + Deleted = false, + }; + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + + //Act + await _customFieldManager.CreateFieldAsync(audit, createCustomField, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences, Has.Count.EqualTo(1)); + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(_fakeCustomFieldRepository!.CustomFields[0].MinEntries, Is.EqualTo(1)); + Assert.That(_fakeCustomFieldRepository!.CustomFields[0].MaxEntries, Is.EqualTo(1)); + }); + } + + [Test] + public async Task CreateCustomField_WithFieldTypeGlossary_SaveChanges() + { + //Arrange + var glossaryId = new Guid("7c5bd569-babf-45b5-9758-69e196b62446"); + var createCustomField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Glossary, + RefElementId = new GeneralIdRef + { + Guid = glossaryId, + }, + + Guid = null, + Name = "FormGuid", + MinEntries = 1, + MaxEntries = 1, + + }; + var glossary = new Glossary + { + Id = 1, + Name = "Some", + Parent = null!, + Guid = glossaryId + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + + //Act + await _customFieldManager.CreateFieldAsync(auditResult, createCustomField, default); + + //Assert + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(1)); + } + + [TestCase(0)] + [TestCase(2)] + public void CreateCustomField_SequenceWithMinEntriesNotSetToOne_ThrowsException(int minEntries) + { + //Arrange + var sequence = new Sequence + { + Id = 1, + Deleted = false, + Guid = new Guid("206894df-2b4e-4a6f-98e1-401b539350b4"), + Name = "Form Name" + }; + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + var customField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Sequence, + RefElementId = new GeneralIdRef + { + Guid = null, + Id = 1 + }, + Guid = null, + Name = "SequenceTest", + MaxEntries = 1, + MinEntries = minEntries, + }; + + //Assert + var exception = Assert.ThrowsAsync(async () => + { + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customField, default); + }); + + Assert.Multiple(() => + { + Assert.That(exception.ParamName, Is.EqualTo("MinEntries")); + Assert.That(exception.Message, + Is.EqualTo("Must be 1 for fields of type Sequence (Parameter 'MinEntries')")); + }); + } + + [TestCase(0)] + [TestCase(2)] + public void CreateCustomField_SequenceWithMaxEntriesNotSetToOne_ThrowsException(int maxEntries) + { + //Arrange + var sequence = new Sequence + { + Id = 1, + Deleted = false, + Guid = new Guid("ac8e9727-f43b-43f1-8fb9-0b3dbc1f41d9"), + Name = "Form Name" + }; + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + var customField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Sequence, + RefElementId = new GeneralIdRef + { + Guid = null, + Id = 1 + }, + Guid = null, + Name = "SequenceTest", + MaxEntries = maxEntries, + MinEntries = 1, + }; + + //Assert + var exception = Assert.ThrowsAsync(async() => + { + //Act + await _customFieldManager.CreateFieldAsync(auditResult, customField, default); + }); + + Assert.Multiple(() => + { + Assert.That(exception.ParamName, Is.EqualTo("MaxEntries")); + Assert.That(exception.Message, + Is.EqualTo("Must be 1 for fields of type Sequence (Parameter 'MaxEntries')")); + }); + } + + [Test] + public void CreateCustomField_WithFieldTypeNumber_WhenParametersNotSupplied_ThrowsException() + { + //Arrange + var glossaryId = new Guid("7fde94f2-6105-4201-a2f4-45dcf70955c6"); + var createCustomField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Number, + + Guid = null, + Name = "FormGuid", + MinEntries = 1, + MaxEntries = 1, + + }; + var glossary = new Glossary + { + Id = 1, + Name = "Some", + Parent = null!, + Guid = glossaryId + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await _customFieldManager.CreateFieldAsync(auditResult, createCustomField, default); + } + ); + } + + [Test] + public async Task CreateCustomField_WithFieldTypeNumber_WhenParametersSupplied_SavesOk() + { + //Arrange + var glossaryId = new Guid("7fde94f2-6105-4201-a2f4-45dcf70955c6"); + var createCustomField = new CreateCustomField + { + DefaultValue = "1", + FieldType = FieldType.Number, + + Guid = null, + Name = "FormGuid", + MinEntries = 1, + MaxEntries = 1, + Parameters = "{ \"minValue\":\"2.3\", \"maxValue\": \"99.99\", \"step\": \"0.2\" }" + }; + var glossary = new Glossary + { + Id = 1, + Name = "Some", + Parent = null!, + Guid = glossaryId + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + + //Act + await _customFieldManager.CreateFieldAsync(auditResult, createCustomField, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldNumber, Has.Count.EqualTo(1)); + var number = _fakeCustomFieldReferenceRepository.CustomFieldNumber[0]; + Assert.That(number.MinimumValue, Is.EqualTo(2.3)); + Assert.That(number.MaximumValue, Is.EqualTo(99.99)); + Assert.That(number.Step, Is.EqualTo(0.2)); + }); + } +} diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/DeactivateCustomFieldUnitTest.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/DeactivateCustomFieldUnitTest.cs new file mode 100644 index 0000000..6726e7a --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/DeactivateCustomFieldUnitTest.cs @@ -0,0 +1,87 @@ +using e_suite.API.Common.exceptions; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldManagerUnitTests; + +public class DeactivateCustomFieldUnitTest : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public void Deactivate_NoMachingId_ThrowsException() + { + var guid = Guid.NewGuid(); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = guid, + Name = "Test", + Id = 5, + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + _customFieldManager = new CustomFieldManager(_fakeCustomFieldRepository, _customFieldReferenceObjectRepository.Object, _customFieldHelper); + Assert.ThrowsAsync(() => _customFieldManager.DeleteFieldAsync(auditResult, new GeneralIdRef { Guid = Guid.NewGuid() }, default)); + } + + [Test] + public async Task Deactivate_NormalContidions_SaveChanges() + { + var guid = Guid.NewGuid(); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = guid, + Name = "Test", + Id = 5, + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + await _customFieldManager.DeleteFieldAsync(auditResult, new GeneralIdRef { Guid = guid }, default); + Assert.That(customField.Deleted, Is.EqualTo(true)); + } + + [Test] + public void DeactivateNotexistingCustomfieldthrowsException() + { + _customFieldManager = new CustomFieldManager(_fakeCustomFieldRepository, _customFieldReferenceObjectRepository.Object, _customFieldHelper); + Assert.ThrowsAsync(() => _customFieldManager.DeleteFieldAsync(auditResult, new GeneralIdRef { Guid = Guid.NewGuid() }, default)); + } + + [Test] + public void Deactivate_AlreadyDeactivatedField_ThrowsException() + { + var guid = Guid.NewGuid(); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = true, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = guid, + Name = "Test", + Id = 5, + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + Assert.ThrowsAsync(() => _customFieldManager.DeleteFieldAsync(auditResult, new GeneralIdRef { Guid = guid }, default)); + } + + [Test] + public async Task Deactivate_OnlyGivenByIdNoGuid_SaveChanges() + { + var guid = Guid.NewGuid(); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = guid, + Name = "Test", + Id = 5, + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + await _customFieldManager.DeleteFieldAsync(auditResult, new GeneralIdRef { Id = 5, Guid = null }, default); + Assert.That(customField.Deleted, Is.EqualTo(true)); + } +} diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/EditCustomFieldlUnitTests.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/EditCustomFieldlUnitTests.cs new file mode 100644 index 0000000..81e382a --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/EditCustomFieldlUnitTests.cs @@ -0,0 +1,1141 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.CustomFields; +using Sequence = e_suite.Database.Core.Tables.Sequences.Sequence; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldManagerUnitTests; + +public class EditCustomFieldUnitTests : CustomFieldsTestBase +{ + + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public void EditCustomField_NoRefObj_ThrowsNameExistsException() + { + var customFieldInDb = new CustomField + { + DefaultValue = "test", + FieldType = eSuite.Core.CustomFields.FieldType.Time, + Name = "NameExists", + Id = 10 + }; + + var customField = new CustomField + { + DefaultValue = "testOne", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "TestOrg", + Id = 15 + }; + _fakeCustomFieldRepository.CustomFields.Add(customFieldInDb); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + var editCustomField = new EditCustomFields + { + DefaultValue = "Testt", + Name = "NameExists", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Id = new GeneralIdRef + { + Guid = null, + Id = 15 + } + }; + Assert.ThrowsAsync(() => _customFieldManager.EditFieldAsync(auditResult, editCustomField, default)); + } + + [Test] + public void EditCustomField_UnexistingId_ThrowsExeption() + { + var baseGuid = new Guid("dfeeb83d-d12d-439d-a6c4-7ff987467d8d"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = baseGuid, + Name = "Test", + Id = 5, + }; ; + _fakeCustomFieldRepository.CustomFields.Add(customField); + var editcustomField = new EditCustomFields + { + DefaultValue = "some", + FieldType = eSuite.Core.CustomFields.FieldType.FormTemplate, + Name = "Someee", + Id = new GeneralIdRef + { + Guid = new Guid("47bc6bf4-9afc-407e-ad13-b6f90cb84e1b"), + Id = 2 + }, + }; + Assert.ThrowsAsync(() => _customFieldManager.EditFieldAsync(auditResult, editcustomField, default)); + } + + [Test] + public async Task EditCustomField_NormalConditions_SaveChanges() + { + var baseGuid = new Guid("c1aa4f0a-a0c7-4c54-a72c-4ae5d5ccbd7b"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = baseGuid, + Name = "Test", + Id = 5, + MinEntries = 10, + MaxEntries = 10 + }; + + _fakeCustomFieldRepository.CustomFields.Add(customField); + var res = await _fakeCustomFieldRepository.GetByIdAsync(new GeneralIdRef + { + Guid = baseGuid, + Id = 5 + }, default); + Assert.Multiple(() => + { + Assert.That(res?.DefaultValue, Is.EqualTo(customField.DefaultValue)); + Assert.That(res!.Name, Is.EqualTo(customField.Name)); + Assert.That(res!.MinEntries, Is.EqualTo(10)); + Assert.That(res.MaxEntries, Is.EqualTo(10)); + }); + } + + [Test] + public async Task EditCustomField_AllPossibleFieldValuesSetToNull_SaveChanges() + { + var baseGuid = new Guid("ee47538e-77f3-4b0b-ad9a-7871eed1884c"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = baseGuid, + Name = "Test", + Id = 5, + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + var editCustomField = new EditCustomFields + { + DefaultValue = "some", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "Name", + Id = new GeneralIdRef + { + Guid = baseGuid, + Id = 5 + }, + Parameters = "{\"multiLine\":false}" + }; + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + var res = await _fakeCustomFieldRepository.GetByIdAsync(new GeneralIdRef + { + Guid = baseGuid, + Id = 5 + }, default); + Assert.Multiple(() => + { + Assert.That(res?.DefaultValue, Is.EqualTo("some")); + Assert.That(res!.Name, Is.EqualTo("Name")); + }); + } + + [Test] + public void EditCustomField_NullForGuidAndId_ThrowsException() + { + var baseGuid = new Guid("f2c1a107-a748-410d-9192-aebac5151207"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = baseGuid, + Name = "Test", + Id = 5, + }; ; + _fakeCustomFieldRepository.CustomFields.Add(customField); + var editcustomField = new EditCustomFields + { + DefaultValue = "some", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "name", + Id = new GeneralIdRef + { + Guid = null, + Id = null + }, + }; + Assert.ThrowsAsync(() => _customFieldManager.EditFieldAsync(auditResult, editcustomField, default)); + } + + [Test] + public async Task EditCustomField_IdFieldOnlyHasIdNoGuid_SaveChanges() + { + var baseGuid = new Guid("7de35ae2-0cb2-44a0-a98b-6eff6097b156"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = baseGuid, + Name = "Test", + Id = 5, + }; ; + _fakeCustomFieldRepository.CustomFields.Add(customField); + var editcustomField = new EditCustomFields + { + DefaultValue = "Tessst", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "Some1", + Id = new GeneralIdRef + { + Guid = null, + Id = 5 + }, + Parameters = "{\"multiLine\":false}" + }; + await _customFieldManager.EditFieldAsync(auditResult, editcustomField, default); + var res = await _fakeCustomFieldRepository.GetByIdAsync(new GeneralIdRef + { + Guid = null, + Id = 5 + }, default); + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(res!.DefaultValue, Is.EqualTo("Tessst")); + Assert.That(res.Name, Is.EqualTo("Some1")); + }); + } + + [Test] + public async Task EditCustomField_DifferentReferenceSequenceNoRefObjForDeletion_SaveChanges() + { + var customFieldId = new Guid("3c0b6eeb-dfa3-4539-995f-b94b067d861d"); + var sequenceGuid = new Guid("fcf96e58-c00d-4ba2-baae-6e6bedc923f7"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "Test", + Guid = customFieldId, + Id = 1, + MinEntries = 1, + MaxEntries = 1 + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "Testtt", + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "Test111111", + RefElementId = new GeneralIdRef + { + Guid = sequenceGuid, + Id = 5, + }, + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + MinEntries = 1, + MaxEntries = 1 + }; + + var sequence = new Sequence + { + Guid = sequenceGuid, + Id = 5, + Deleted = false, + Name = "NameSequence", + Increment = 1, + }; + + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences, Has.Count.EqualTo(1)); + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(_fakeCustomFieldRepository.CustomFields[0].Name, Is.EqualTo("Test111111")); + }); + } + + [Test] + public async Task EditCustomField_DifferentReferenceGlossaryNoneObjForDeletion_SaveChanges() + { + var customFieldId = new Guid("b57ede2d-5f21-4399-9b17-7ba356daf32d"); + var glossaryId = new Guid("b87a3a12-6e20-43ac-a54c-3188213109c9"); + + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "Test", + Guid = customFieldId, + Id = 1, + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "au", + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Name = "TestSSSTest", + RefElementId = new GeneralIdRef + { + Guid = glossaryId, + Id = 5, + }, + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + + }; + + var glossary = new Glossary + { + Guid = glossaryId, + Id = 5, + Deleted = false, + Name = "NameForm", + }; + + _fakeCustomFieldRepository.CustomFields.Add(customField); + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(1)); + Assert.That(_fakeCustomFieldRepository.CustomFields[0].Name, Is.EqualTo("TestSSSTest")); + Assert.That(_fakeCustomFieldRepository.CustomFields[0].DefaultValue, Is.EqualTo("au")); + }); + } + + [Test] + public async Task EditCustomField_CustomFieldWithSequenceReferenceToBasicType_SaveChanges() + { + var customFieldId = new Guid("7dc5e45f-cc56-4e71-942c-6463b7bd43d5"); + var sequenceGuid = new Guid("0a344546-1f57-4bd2-8ffa-105ebffb9719"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "Test", + Guid = customFieldId, + Id = 1, + }; + + var sequence = new Sequence + { + Guid = sequenceGuid, + Id = 5, + Deleted = false, + Name = "NameSequence", + Increment = 1, + }; + + var customFieldSequence = new CustomFieldSequence + { + CustomFieldId = 1, + SequenceId = 5 + }; + + var editCustomFeild = new EditCustomFields + { + DefaultValue = "FEF", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "FEFName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + Parameters = "{\"multiLine\":false}" + }; + + _fakeCustomFieldRepository.CustomFields.Add(customField); + _fakeCustomFieldReferenceRepository.CustomFieldSequences.Add(customFieldSequence); + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomFeild, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences, Has.Count.EqualTo(0)); + Assert.That(customField.Name, Is.EqualTo("FEFName")); + Assert.That(customField.DefaultValue, Is.EqualTo("FEF")); + }); + + } + + [Test] + public async Task EditCustomField_CustomFieldWithGlossaryReferenceToBasicType_SaveChanges() + { + var customFieldId = new Guid("f4449135-acf5-427b-8597-a29c2a46c7c9"); + var glossaryGuid = new Guid("7ff16821-c1f8-476f-8b5d-c48100674b02"); + var customField = new CustomField + { + DefaultValue = "asdasd", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Name = "Test", + Guid = customFieldId, + Id = 1, + }; + + var glossary = new Glossary + { + Guid = glossaryGuid, + Id = 5, + Deleted = false, + Name = "NameSequence", + Parent = null! + }; + + var customFieldGlossary = new CustomFieldGlossary + { + CustomFieldId = 1, + GlossaryId = 5 + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "FEF", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "FEFName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + Parameters = "{\"multiLine\":false}" + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + _fakeCustomFieldRepository.CustomFields.Add(customField); + _fakeCustomFieldReferenceRepository.CustomFieldGlossaries.Add(customFieldGlossary); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(0)); + Assert.That(customField.Name, Is.EqualTo("FEFName")); + Assert.That(customField.DefaultValue, Is.EqualTo("FEF")); + }); + } + + [Test] + public async Task EditCustomField_CustomFieldWithFormReferenceToCreateOneGlossaryAndDeleteFormObj_SaveChanges() + { + var customFieldId = new Guid("b1d17211-1399-4a1c-ae03-fed49c649426"); + var formGuid = new Guid("65dc687e-c8bb-4288-b0c6-b7f39cfde836"); + var glossaryGuid = new Guid("d416496f-d0f2-4ee3-a821-afb8c3bd0a14"); + var customField = new CustomField + { + DefaultValue = "FormTemplateValue", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.FormTemplate, + Name = "FormName", + Guid = customFieldId, + Id = 1, + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "GlossaryDefault", + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Name = "FEGlossaryName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = new GeneralIdRef + { + Id = 20, + Guid = glossaryGuid + }, + MinEntries = 10, + MaxEntries = 10, + }; + + var glossary = new Glossary + { + Guid = glossaryGuid, + Deleted = false, + Name = "gloss", + Id = 20 + }; + + var formTemplate = new FormTemplate + { + Guid = formGuid, + Id = 5, + Deleted = false, + Name = "NameForm", + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + _fakeCustomFieldReferenceRepository.FormTemplates.Add(formTemplate); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(1)); + Assert.That(customField.Name, Is.EqualTo("FEGlossaryName")); + Assert.That(customField.DefaultValue, Is.EqualTo("GlossaryDefault")); + Assert.That(customField.MaxEntries, Is.EqualTo(10)); + Assert.That(customField.MinEntries, Is.EqualTo(10)); + }); + } + + [Test] + public async Task EditCustomField_CustomFieldWithGlossaryReferenceToCreateOneSequenceAndDeleteGlossaryObj_SaveChanges() + { + var customFieldId = new Guid("64661af7-ef5a-4ee1-84e5-59327ff62625"); + var glossaryGuid = new Guid("a3ad8c4e-112d-41fc-881e-e450b84c5c12"); + var sequenceGuid = new Guid("36ca4348-a779-485d-9d90-04766207d2a1"); + var customField = new CustomField + { + DefaultValue = "GlossaryValue", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Name = "Glosss", + Guid = customFieldId, + Id = 1, + MaxEntries = 1, + MinEntries = 1, + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "SequenceDef", + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "SequenceName", + MinEntries = 1, + MaxEntries = 1, + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = new GeneralIdRef + { + Id = 20, + Guid = sequenceGuid + } + }; + + var customFieldGlossary = new CustomFieldGlossary + { + CustomFieldId = 1, + GlossaryId = 5 + }; + + var sequence = new Sequence + { + Guid = sequenceGuid, + Deleted = false, + Name = "Dasda", + Id = 20, + Increment = 5 + }; + + var glossary = new Glossary + { + Guid = glossaryGuid, + Id = 5, + Deleted = false, + Name = "NEwGloss", + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + _fakeCustomFieldReferenceRepository.CustomFieldGlossaries.Add(customFieldGlossary); + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences, Has.Count.EqualTo(1)); + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(0)); + Assert.That(customField.Name, Is.EqualTo("SequenceName")); + Assert.That(customField.DefaultValue, Is.EqualTo("SequenceDef")); + Assert.That(customField.MaxEntries, Is.EqualTo(1)); + Assert.That(customField.MinEntries, Is.EqualTo(1)); + }); + } + + [Test] + public async Task EditCustomField_CustomFieldWithSequenceReferenceToCreateOneGlossaryAndDeleteSequenceObj_SaveChanges() + { + var customFieldId = new Guid("fc281499-2991-4d04-9bc1-f833be690f80"); + var glossaryGuid = new Guid("b0b816a7-63b1-485d-b067-1ae3edd3ff6e"); + var sequenceGuid = new Guid("a0c63632-4ee7-44a1-a18d-128414a0a262"); + var customField = new CustomField + { + DefaultValue = "Sequencevalue", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "Sequ", + Guid = customFieldId, + Id = 1, + MinEntries = 1, + MaxEntries = 1, + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "GloosaryDef", + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Name = "GlossaryName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = new GeneralIdRef + { + Id = 5, + Guid = glossaryGuid + }, + MinEntries = 10, + MaxEntries = 10, + }; + + var customFieldSequence = new CustomFieldSequence + { + CustomFieldId = 1, + SequenceId = 20 + }; + + var sequence = new Sequence + { + Guid = sequenceGuid, + Deleted = false, + Name = "Dasda", + Id = 20, + Increment = 5 + }; + + var glossary = new Glossary + { + Guid = glossaryGuid, + Id = 5, + Deleted = false, + Name = "NEwGloss", + }; + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + _fakeCustomFieldReferenceRepository.Sequences.Add(sequence); + _fakeCustomFieldReferenceRepository.CustomFieldSequences.Add(customFieldSequence); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences, Has.Count.EqualTo(0)); + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(1)); + Assert.That(customField.Name, Is.EqualTo("GlossaryName")); + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(customField.MaxEntries, Is.EqualTo(10)); + Assert.That(customField.MinEntries, Is.EqualTo(10)); + }); + } + + [Test] + public async Task EditCustomField_CustomFieldWithGlossaryReferenceToTestType_SaveChanges() + { + var customFieldId = new Guid("e9ccf611-2900-4dad-8850-27c89a3571a3"); + var glossaryGuid = new Guid("a983587c-0d71-47c0-b967-f2ae181c490f"); + + var customField = new CustomField + { + DefaultValue = "DefaultStart", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Guid = customFieldId, + Id = 1, + Name = "NameStart", + MinEntries = 1, + MaxEntries = 1, + }; + + var glossary = new Glossary + { + Guid = glossaryGuid, + Id = 5, + Deleted = false, + Name = "NEwGloss", + }; + + var customFieldGlossary = new CustomFieldGlossary + { + CustomFieldId = 1, + GlossaryId = 5 + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "EditValue", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "EditName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + MinEntries = 10, + MaxEntries = 10, + Parameters = "{\"multiLine\":false}" + }; + _fakeCustomFieldReferenceRepository.CustomFieldGlossaries.Add(customFieldGlossary); + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossary); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries, Has.Count.EqualTo(0)); + Assert.That(customField.Name, Is.EqualTo("EditName")); + Assert.That(customField.DefaultValue, Is.EqualTo("EditValue")); + Assert.That(customField.MaxEntries, Is.EqualTo(10)); + Assert.That(customField.MinEntries, Is.EqualTo(10)); + }); + } + + [Test] + public async Task EditCustomField_SameObjReferenceUpdateReferenceGlossary_SaveChanges() + { + var customFieldId = new Guid("4dcbac9a-0e8b-4022-be66-bca94e1fa0c3"); + var glossaryGuidOld = new Guid("e11f3a48-8e43-4c56-a7ea-0e3ddb96ae21"); + var glossaryGuidNew = new Guid("d748a83e-0343-48e1-939e-c27db2289c6d"); + + var customField = new CustomField + { + DefaultValue = "DefaultStart", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Guid = customFieldId, + Id = 1, + Name = "NameStart", + MinEntries = 1, + MaxEntries = 1, + }; + + var glossaryOld = new Glossary + { + Deleted = false, + Guid = glossaryGuidOld, + Id = 5, + Name = "Before" + }; + + var glossaryNew = new Glossary + { + Deleted = false, + Guid = glossaryGuidNew, + Id = 10, + Name = "New" + }; + + var customFieldGlossary = new CustomFieldGlossary + { + CustomFieldId = 1, + GlossaryId = 10 + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "NewGlossDef", + FieldType = eSuite.Core.CustomFields.FieldType.Glossary, + Name = "NewGlossName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = new GeneralIdRef + { + Id = 10, + Guid = glossaryGuidNew + }, + MinEntries = 10, + MaxEntries = 10, + }; + _fakeCustomFieldReferenceRepository.CustomFieldGlossaries.Add(customFieldGlossary); + _fakeCustomFieldRepository.CustomFields.Add(customField); + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossaryOld); + _fakeCustomFieldReferenceRepository.Glossaries.Add(glossaryNew); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldGlossaries[0].GlossaryId, Is.EqualTo(10)); + Assert.That(customField.Name, Is.EqualTo("NewGlossName")); + Assert.That(customField.DefaultValue, Is.EqualTo("NewGlossDef")); + Assert.That(customField.MaxEntries, Is.EqualTo(10)); + Assert.That(customField.MinEntries, Is.EqualTo(10)); + }); + + } + + [Test] + public async Task EditCustomField_SameObjReferenceUpdateReferenceSequence_SaveChanges() + { + var customFieldId = new Guid("a14ae0dd-12e8-4788-961f-25cdaa70f40f"); + var sequenceGuidOld = new Guid("8ef35a06-96cf-40d5-92be-597913d4ad1c"); + var sequenceGuidNew = new Guid("576d202c-31e3-44f4-8ca6-23518951567b"); + + var customField = new CustomField + { + DefaultValue = "DefaultStart", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Guid = customFieldId, + Id = 1, + Name = "NameStart", + MinEntries = 1, + MaxEntries = 1, + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "NewSequenceDef", + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "NewSequenceName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = new GeneralIdRef + { + Id = 10, + Guid = sequenceGuidNew + }, + MinEntries = 1, + MaxEntries = 1, + }; + + var sequenceOld = new Sequence + { + Deleted = false, + Name = "OldSeq", + Guid = sequenceGuidOld, + Id = 5, + Seed = 1 + }; + + var sequenceNew = new Sequence + { + Deleted = false, + Name = "NewSeq", + Guid = sequenceGuidNew, + Id = 10, + Seed = 1 + }; + + var customFieldSequence = new CustomFieldSequence + { + CustomFieldId = 1, + SequenceId = 5 + }; + + _fakeCustomFieldReferenceRepository.Sequences.AddRange(new Sequence[] { sequenceOld, sequenceNew }); + _fakeCustomFieldReferenceRepository.CustomFieldSequences.Add(customFieldSequence); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + + Assert.Multiple(() => + { + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldSequences[0].SequenceId, Is.EqualTo(10)); + Assert.That(customField.Name, Is.EqualTo("NewSequenceName")); + Assert.That(customField.DefaultValue, Is.EqualTo("NewSequenceDef")); + Assert.That(customField.MaxEntries, Is.EqualTo(1)); + Assert.That(customField.MinEntries, Is.EqualTo(1)); + }); + } + + [Test] + public void EditCustomField_SameObjectTypeReferenceWithUnexistingRefObject_ThrowsException() + { + var customFieldId = new Guid("439c1876-61b7-44df-b516-1107c52152c2"); + var sequenceGuidOld = new Guid("c0bdd715-4bf6-41fa-b2e0-168181170491"); + var sequenceGuidNew = new Guid("5e3b96fd-77aa-48d5-bf1c-a69f3d6d0c17"); + + var customField = new CustomField + { + DefaultValue = "DefaultStart", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Guid = customFieldId, + Id = 1, + Name = "NameStart", + MinEntries = 1, + MaxEntries = 1, + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "NewSequenceDef", + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "NewSequenceName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = new GeneralIdRef + { + Id = 10, + Guid = sequenceGuidNew + }, + MinEntries = 10, + MaxEntries = 10, + }; + + var sequenceOld = new Sequence + { + Deleted = false, + Name = "OldSeq", + Guid = sequenceGuidOld, + Id = 5, + Seed = 1 + }; + + var customFieldSequence = new CustomFieldSequence + { + CustomFieldId = 1, + SequenceId = 5 + }; + + _fakeCustomFieldReferenceRepository.Sequences.Add(sequenceOld); + _fakeCustomFieldReferenceRepository.CustomFieldSequences.Add(customFieldSequence); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + Assert.ThrowsAsync(() => _customFieldManager.EditFieldAsync(auditResult, editCustomField, default)); + } + + [Test] + public void EditCustomField_EditFieldWithReferenceNull_ThrowsException() + { + + var customFieldId = new Guid("8952dfb2-6c08-4bbc-8b61-2e66b90a3558"); + var sequenceGuidOld = new Guid("158d8946-76ee-44b4-bcb2-5390bc4d606a"); + var sequenceGuidNew = new Guid("b359cc4d-3c7c-4b1f-9933-2c5921530c9f"); + + var customField = new CustomField + { + DefaultValue = "DefaultStart", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Guid = customFieldId, + Id = 1, + Name = "NameStart" + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "NewSequenceDef", + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "NewSequenceName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = null! + }; + + var sequenceOld = new Sequence + { + Deleted = false, + Name = "OldSeq", + Guid = sequenceGuidOld, + Id = 5, + Seed = 1 + }; + + _fakeCustomFieldReferenceRepository.Sequences.Add(sequenceOld); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + Assert.ThrowsAsync(() => _customFieldManager.EditFieldAsync(auditResult, editCustomField, default)); + } + + [Test] + public void EditCustomField_EditFieldWithReferenceNullSecondWay_ThrowsException()//TOdo Fix name(im dry out of ideas) + { + //Arrange + var customFieldId = new Guid("3fe78133-cf5f-47fb-b14e-1ba3d19a9867"); + var sequenceGuidOld = new Guid("8705dadc-bd58-45d8-9ede-2515868b081b"); + var sequenceGuidNew = new Guid("277fa0e0-b9f4-4afb-b9bd-0149653d9726"); + + var customField = new CustomField + { + DefaultValue = "DefaultStart", + Deleted = false, + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Guid = customFieldId, + Id = 1, + Name = "NameStart" + }; + + var editCustomField = new EditCustomFields + { + DefaultValue = "NewSequenceDef", + FieldType = eSuite.Core.CustomFields.FieldType.Sequence, + Name = "NewSequenceName", + Id = new GeneralIdRef + { + Id = 1, + Guid = customFieldId + }, + RefElementId = null! + }; + + var sequenceOld = new Sequence + { + Deleted = false, + Name = "OldSeq", + Guid = sequenceGuidOld, + Id = 5, + Seed = 1 + }; + + _fakeCustomFieldReferenceRepository.Sequences.Add(sequenceOld); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + //Assert + Assert.ThrowsAsync(async() => + { + //Act + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, default); + }); + } + + [Test] + public async Task EditCustomField_EditNumberFieldToText_DeletesCustomNumberEntry() + { + //Arrange + var customField = new CustomField + { + Guid = new Guid("89977847-5693-4f4b-8a8a-e576d0b6da4c"), + Id = 1, + FieldType = FieldType.Number, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty, + Deleted = false, + Name = "Test custom field" + }; + + _fakeCustomFieldRepository.CustomFields.Add(customField); + + var customFieldNumber = new CustomFieldNumber + { + CustomField = customField, + CustomFieldId = customField.Id, + MaximumValue = 200, + MinimumValue = 0, + Step = null + }; + _fakeCustomFieldReferenceRepository.CustomFieldNumber.Add(customFieldNumber); + + + var editCustomField = new EditCustomFields + { + DefaultValue = "", + FieldType = FieldType.Text, + Name = "Test custom field", + Id = new GeneralIdRef + { + Id = customField.Id, + Guid = customField.Guid + }, + Parameters = "{\"multiLine\":false}" + }; + + //Act + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, CancellationToken.None); + + //Assert + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldNumber.Count, Is.EqualTo(0)); + } + + [Test] + public async Task EditCustomField_EditNumberField_ReplacesExpectedValues() + { + //Arrange + var customField = new CustomField + { + Guid = new Guid("89977847-5693-4f4b-8a8a-e576d0b6da4c"), + Id = 1, + FieldType = FieldType.Number, + MinEntries = 1, + MaxEntries = 1, + DefaultValue = string.Empty, + Deleted = false, + Name = "Test custom field" + }; + + _fakeCustomFieldRepository.CustomFields.Add(customField); + + var customFieldNumber = new CustomFieldNumber + { + CustomField = customField, + CustomFieldId = customField.Id, + MaximumValue = 200, + MinimumValue = 0, + Step = null + }; + _fakeCustomFieldReferenceRepository.CustomFieldNumber.Add(customFieldNumber); + + + var editCustomField = new EditCustomFields + { + DefaultValue = "", + FieldType = FieldType.Number, + Name = "Test custom field", + Id = new GeneralIdRef + { + Id = customField.Id, + Guid = customField.Guid + }, + Parameters = "{ \"minValue\":\"2.3\", \"maxValue\": \"99.99\", \"step\": \"0.2\" }" + }; + + //Act + await _customFieldManager.EditFieldAsync(auditResult, editCustomField, CancellationToken.None); + + //Assert + Assert.That(_fakeCustomFieldReferenceRepository.CustomFieldNumber.Count, Is.EqualTo(1)); + var editedResult = _fakeCustomFieldReferenceRepository.CustomFieldNumber[0]; + + Assert.That(editedResult.MinimumValue, Is.EqualTo(2.3)); + Assert.That(editedResult.MaximumValue, Is.EqualTo(99.99)); + Assert.That(editedResult.Step, Is.EqualTo(0.2)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetCustomByIdFieldUnitTest.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetCustomByIdFieldUnitTest.cs new file mode 100644 index 0000000..3b7d0f5 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetCustomByIdFieldUnitTest.cs @@ -0,0 +1,119 @@ +using e_suite.API.Common.exceptions; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldManagerUnitTests; + +public class GetCustomByIdFieldUnitTest : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetCustomField_GuidIdOnly_ReturnsCustomField() + { + var guid = Guid.NewGuid(); + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = false, + DefaultValue = "testtt", + Guid = guid, + Id = 15, + Name = "testtName" + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + var idGetCustomIdField = new GeneralIdRef + { + Guid = guid, + Id = null + }; + var res = await _customFieldManager.GetFieldAsync(idGetCustomIdField, default); + + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(res.Name, Is.EqualTo("testtName")); + Assert.That(res.FieldType, Is.EqualTo(eSuite.Core.CustomFields.FieldType.Text)); + }); + } + + [Test] + public async Task GetCustomField_IdOnly_ReturnsCustomField() + { + var guid = Guid.NewGuid(); + var id = 15; + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = false, + DefaultValue = "TT", + Guid = guid, + Id = 15, + Name = "Second" + }; + var idGetCustomIdField = new GeneralIdRef + { + Guid = null, + Id = id + }; + _fakeCustomFieldRepository.CustomFields.Add(customField); + + var res = await _customFieldManager.GetFieldAsync(idGetCustomIdField, default); + + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(res.DefaultValue, Is.EqualTo("TT")); + Assert.That(res.Guid, Is.EqualTo(guid)); + }); + } + + [Test] + public void GetCustomField_WhenDeletedIsTrue_ThrowsFieldNotFoundException() + { + var guid = Guid.NewGuid(); + var id = 15; + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = true, + DefaultValue = "TT", + Guid = guid, + Id = id, + Name = "Second" + }; + var idGetCustomIdField = new GeneralIdRef + { + Guid = guid, + Id = null + }; + _customFieldRepository.Setup(r => r.GetByIdAsync(It.Is(x => x.Guid == guid),It.IsAny())).ReturnsAsync(customField); + Assert.ThrowsAsync(() => _customFieldManager.GetFieldAsync(idGetCustomIdField, default)); + } + + [Test] + public void GetCustomField_NullValuesForFullId_ThrowsFieldNotFoundException() + { + var guid = Guid.NewGuid(); + var id = 15; + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = true, + DefaultValue = "TT", + Guid = guid, + Id = id, + Name = "Second" + }; + var idGetCustomIdField = new GeneralIdRef + { + Guid = null, + Id = null + }; + _customFieldRepository.Setup(r => r.GetByIdAsync(It.Is(x => x.Id != null || x.Guid != null), It.IsAny())).ReturnsAsync(customField); + Assert.ThrowsAsync(() => _customFieldManager.GetFieldAsync(idGetCustomIdField,default)); + } + +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetFieldByNameUnitTest.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetFieldByNameUnitTest.cs new file mode 100644 index 0000000..0a16605 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetFieldByNameUnitTest.cs @@ -0,0 +1,71 @@ +using e_suite.API.Common.exceptions; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldManagerUnitTests; + +public class GetFieldByNameUnitTest : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task GetCustomField_AllNormal_ReturnsCustomField() + { + var guid = Guid.NewGuid(); + var name = "testtName"; + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = false, + DefaultValue = "testtt", + Guid = guid, + Id = 15, + Name = name, + }; + _customFieldManager = new CustomFieldManager(_fakeCustomFieldRepository, _customFieldReferenceObjectRepository.Object, _customFieldHelper); + _fakeCustomFieldRepository.CustomFields.Add(customField); + var res = await _customFieldManager.GetFieldAsync(name,default); + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(res.Guid, Is.EqualTo(guid)); + }); + + } + [Test] + public void GetCustomField_WhenDeletedIsTrue_ThrowsFieldNotFoundException() + { + var guid = Guid.NewGuid(); + var id = 15; + var name = "Second"; + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = true, + DefaultValue = "TT", + Guid = guid, + Id = id, + Name = name + }; + _customFieldRepository.Setup(r => r.GetByNameAsync(It.Is(x => x == name), It.IsAny())).ReturnsAsync(customField); + Assert.ThrowsAsync(() => _customFieldManager.GetFieldAsync(name,default)); + } + + [Test] + public void GetCustomField_NullValueForNama_ThrowsFieldNotFoundException() + { + var guid = Guid.NewGuid(); + var id = 15; + string name = "Second"; + var customField = new CustomField + { + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Deleted = true, + DefaultValue = "TT", + Guid = guid, + Id = id, + Name = name + }; + _customFieldRepository.Setup(r => r.GetByNameAsync(It.Is(x => x == name), It.IsAny())).ReturnsAsync(customField); + Assert.ThrowsAsync(() => _customFieldManager.GetFieldAsync((null as string)!,default)); + } +} diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetFieldsAsyncUnitTests.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetFieldsAsyncUnitTests.cs new file mode 100644 index 0000000..43aebd1 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldManagerUnitTests/GetFieldsAsyncUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.Utilities.Pagination; + +namespace e_suite.Modules.CustomFieldManagerUnitTests.CustomFieldManagerUnitTests; + +public class GetFieldsAsyncUnitTests : CustomFieldsTestBase +{ + [SetUp] + public override async Task Setup() => await base.Setup(); + + [Test] + public async Task GetSequences_Called_ReturnsSequenceList() + { + // Arrange + var custFieldInDb = new CustomField + { + DefaultValue = "test", + FieldType = eSuite.Core.CustomFields.FieldType.Time, + Name = "NameExists", + Id = 10 + }; + + var customField = new CustomField + { + DefaultValue = "testOne", + FieldType = eSuite.Core.CustomFields.FieldType.Text, + Name = "TestOrg", + Id = 15 + }; + _fakeCustomFieldRepository.CustomFields.Add(custFieldInDb); + _fakeCustomFieldRepository.CustomFields.Add(customField); + + var paging = new Paging(); + + // Act + var result = await _customFieldManager.GetFieldsAsync(paging, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(2)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldsTestBase.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldsTestBase.cs new file mode 100644 index 0000000..854ba59 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/CustomFieldsTestBase.cs @@ -0,0 +1,34 @@ +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.UnitTestCore; + +namespace e_suite.Modules.CustomFieldManagerUnitTests; + +public class CustomFieldsTestBase : TestBase +{ + protected Mock _customFieldRepository = null!; + protected CustomFieldManager _customFieldManager = null!; + protected FakeCustomFieldRepository _fakeCustomFieldRepository = null!; + protected AuditUserDetails auditResult = null!; + protected Mock _customFieldReferenceObjectRepository = null!; + protected FakeCustomFieldReferenceRepository _fakeCustomFieldReferenceRepository = null!; + protected ICustomFieldHelper _customFieldHelper = null!; + + public override async Task Setup() + { + await base.Setup(); + auditResult = new AuditUserDetails + { + UserId = -1, + UserDisplayName = "Testing User", + Comment = "Test comment" + }; + _customFieldRepository = new Mock(); + _fakeCustomFieldRepository = new FakeCustomFieldRepository(); + _customFieldReferenceObjectRepository = new Mock(); + _fakeCustomFieldReferenceRepository = new FakeCustomFieldReferenceRepository(); + _customFieldHelper = new CustomFieldHelper(_fakeCustomFieldReferenceRepository); + _customFieldManager = new CustomFieldManager(_fakeCustomFieldRepository, _fakeCustomFieldReferenceRepository, _customFieldHelper); + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/FakeCustomFieldReferenceRepository.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/FakeCustomFieldReferenceRepository.cs new file mode 100644 index 0000000..f1d2e79 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/FakeCustomFieldReferenceRepository.cs @@ -0,0 +1,222 @@ +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.UnitTestCore; +using Sequence = e_suite.Database.Core.Tables.Sequences.Sequence; + +namespace e_suite.Modules.CustomFieldManagerUnitTests; + +public class FakeCustomFieldReferenceRepository : FakeRepository, ICustomFieldReferenceObjectRepository +{ + public List CustomFieldFormTemplates { get; set; } = []; + public List CustomFieldGlossaries { get; set; } = []; + + public List CustomFieldSequences { get; set; } = []; + + public List CustomFieldNumber { get; set; } = []; + + public List CustomFieldText { get; set; } = []; + + public List Sequences { get; set; } = []; + + public List Glossaries { get; set; } = []; + + public List Domains { get; set; } = []; + + public List FormTemplates { get; set; } = []; + + public Task CreateFormReferenceAsync(AuditUserDetails auditUserDetails, long customFieldId, long formId, CancellationToken cancellationToken) + { + CustomFieldFormTemplates.Add(new CustomFieldFormTemplate + { + CustomFieldId = customFieldId, + FormTemplateId = formId, + }); + + return Task.CompletedTask; + } + + public Task CreateGlossaryReferenceAsync(AuditUserDetails auditUserDetails, long customField, long glossaryId, CancellationToken cancellationToken) + { + CustomFieldGlossaries.Add(new CustomFieldGlossary + { + GlossaryId = glossaryId, + CustomFieldId = customField, + }); + + return Task.CompletedTask; + } + + public Task CreateDomainReferenceAsync(AuditUserDetails auditUserDetails, long customField, long formId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateSequenceReferenceAsync(AuditUserDetails auditUserDetails, long customField, long sequenceId, CancellationToken cancellationToken) + { + var seq = new CustomFieldSequence + { + CustomFieldId = customField, + SequenceId = sequenceId, + }; + CustomFieldSequences.Add(seq); + return Task.CompletedTask; + } + + + public Task DeleteFormReferenceAsync(AuditUserDetails auditUserDetails, long cusotmFieldId, CancellationToken cancellationToken) + { + var customFieldForm = CustomFieldFormTemplates.FirstOrDefault(x => x.CustomFieldId == cusotmFieldId); + CustomFieldFormTemplates.Remove(customFieldForm!); + return Task.CompletedTask; + } + + public Task DeleteGlossaryReferenceAsync(AuditUserDetails auditUserDetails, long customField, CancellationToken cancellationToken) + { + var customFieldGlossary = CustomFieldGlossaries.FirstOrDefault(g => g.CustomFieldId == customField); + CustomFieldGlossaries.Remove(customFieldGlossary!); + return Task.CompletedTask; + } + + public Task DeleteDomainReferenceAsync(AuditUserDetails auditUserDetails, long customField, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task DeleteSequenceReferenceAsync(AuditUserDetails auditUserDetails, long customFiled, CancellationToken cancellationToken) + { + var customFieldSeq = CustomFieldSequences.FirstOrDefault(x => x.CustomFieldId == customFiled); + CustomFieldSequences.Remove(customFieldSeq!); + return Task.CompletedTask; + } + + + public Task EditFormReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldFormTemplate customFieldFormTemplate, CancellationToken cancellationToken) + { + var customFieldForm = CustomFieldFormTemplates.FirstOrDefault(x => x.CustomFieldId == customFieldFormTemplate.CustomFieldId); + customFieldForm!.FormTemplateId = customFieldFormTemplate.FormTemplateId; + return Task.CompletedTask; + } + + public Task EditGlossaryReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldGlossary customFieldGlossary, CancellationToken cancellationToken) + { + var customFieldGlossaryRef = CustomFieldGlossaries.FirstOrDefault(x => x.CustomFieldId == customFieldGlossary.CustomFieldId); + customFieldGlossaryRef!.GlossaryId = customFieldGlossary.GlossaryId; + return Task.CompletedTask; + } + + public Task EditDomainReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldGlossary customFieldGlossary, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditSequenceReferenceAsync(AuditUserDetails auditUserDetails, CustomFieldSequence customFieldSequence, CancellationToken cancellationToken) + { + var customFieldSequenceRef = CustomFieldSequences.FirstOrDefault(x => x.CustomFieldId == customFieldSequence.CustomFieldId); + customFieldSequenceRef!.SequenceId = customFieldSequence.SequenceId; + return Task.CompletedTask; + } + + + public Task GetFormReferenceAsync(long customFieldId, CancellationToken cancellationToken) + { + var res = CustomFieldFormTemplates.FirstOrDefault(x => x.CustomFieldId == customFieldId); + return Task.FromResult(res); + } + + public Task GetSequenceReferenceAsync(long customFieldId, CancellationToken cancellationToken) + { + var res = CustomFieldSequences.FirstOrDefault(x => x.CustomFieldId == customFieldId); + return Task.FromResult(res); + } + + public Task GetGlossaryReferenceAsync(long cusotmFieldId, CancellationToken cancellationToken) + { + return Task.FromResult(CustomFieldGlossaries.FirstOrDefault(x => x.CustomFieldId == cusotmFieldId)); + } + + public Task GetNumbersParametersAsync(long customFieldId, CancellationToken cancellationToken) + { + return Task.FromResult(CustomFieldNumber.FirstOrDefault(x => x.CustomFieldId == customFieldId)); + } + + public Task CreateCustomFieldNumbersAsync( + AuditUserDetails auditUserDetails, + CustomFieldNumber customFieldNumber, + CancellationToken cancellationToken + ) + { + CustomFieldNumber.Add(customFieldNumber); + return Task.CompletedTask; + } + + public Task EditCustomFieldNumbersAsync( + AuditUserDetails auditUserDetails, + CustomFieldNumber customFieldNumber, + NumberFieldParameters numberFieldParameters, + CancellationToken cancellationToken + ) + { + return Task.CompletedTask; + //Does not need to do anything in the fake repo. + } + + public Task DeleteCustomFieldNumbersAsync( + AuditUserDetails auditUserDetails, + CustomFieldNumber customFieldNumber, + CancellationToken cancellationToken + ) + { + CustomFieldNumber.Remove(customFieldNumber); + return Task.CompletedTask; + } + + public Task GetGlossaryByGeneralRefIdAsync(IGeneralIdRef? idRef, CancellationToken cancellationToken) + { + var res = Glossaries.FirstOrDefault(x => x.Id == idRef?.Id || x.Guid == idRef?.Guid); + return Task.FromResult(res); + } + + public Task GetDomainByGeneralRefIdAsync(IGeneralIdRef? idRef, CancellationToken cancellationToken) + { + var res = Domains.FirstOrDefault(x => x.Id == idRef?.Id || x.Guid == idRef?.Guid); + return Task.FromResult(res); + } + + public Task GetSequenceByGeneralRefIdAsync(IGeneralIdRef? idRef, CancellationToken cancellationToken) + { + var res = Sequences.FirstOrDefault(x => x.Id == idRef?.Id || x.Guid == idRef?.Guid); + return Task.FromResult(res); + } + public Task GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef? idRef, CancellationToken cancellationToken) + { + var res = FormTemplates.FirstOrDefault(x => x.Id == idRef?.Id || x.Guid == idRef?.Guid); + return Task.FromResult(res); + } + + public Task GetTextsParametersAsync(long customFieldId, CancellationToken cancellationToken) + { + return Task.FromResult(CustomFieldText.FirstOrDefault(x => x.CustomFieldId == customFieldId)); + } + + public Task CreateCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, CancellationToken cancellationToken) + { + CustomFieldText.Add(customFieldText); + return Task.CompletedTask; + } + + public Task EditCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, TextFieldParameters textFieldParameters, CancellationToken cancellationToken) + { + return Task.CompletedTask; + //Does not need to do anything in the fake repo. + } + + public Task DeleteCustomFieldTextsAsync(AuditUserDetails auditUserDetails, CustomFieldText customFieldText, CancellationToken cancellationToken) + { + CustomFieldText.Remove(customFieldText); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/FakeCustomFieldRepository.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/FakeCustomFieldRepository.cs new file mode 100644 index 0000000..60d0cfc --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/FakeCustomFieldRepository.cs @@ -0,0 +1,45 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.UnitTestCore; +using eSuite.Core.CustomFields; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.CustomFieldManagerUnitTests; + +public class FakeCustomFieldRepository : FakeRepository, ICustomFieldRepository +{ + public List CustomFields { get; set; } = []; + + public Task CreateAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + CustomFields.Add(customField); + customField.Id = CustomFields.Max(x => x.Id) + 1; + return Task.CompletedTask; + } + + public IQueryable GetCustomFieldList() + { + return CustomFields.Where(x => !x.Deleted).ToList().BuildMock(); + } + + public Task EditAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + var customFieldReal = CustomFields.Single(x => x.Guid == customField.Guid || x.Id == customField.Id); + customFieldReal.Name = customField.Name; + customFieldReal.DefaultValue = customField.DefaultValue; + customFieldReal.FieldType = customField.FieldType; + customFieldReal.Deleted = customField.Deleted; + return Task.CompletedTask; + } + + public Task GetByIdAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + return Task.FromResult(CustomFields.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid)); + } + + public Task GetByNameAsync(string name, CancellationToken cancellationToken) + { + return Task.FromResult(CustomFields.FirstOrDefault(x => x.Name == name)); + } +} diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/Usings.cs b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/Usings.cs new file mode 100644 index 0000000..81e5815 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/Usings.cs @@ -0,0 +1,6 @@ +global using NUnit.Framework; +global using e_suite.Database.Core.Tables.CustomFields; +global using e_suite.Modules.CustomFieldsManager; +global using e_suite.Modules.CustomFieldsManager.Repository; +global using eSuite.Core.Miscellaneous; +global using Moq; \ No newline at end of file diff --git a/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/e_suite.Modules.CustomFieldManagerUnitTests.csproj b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/e_suite.Modules.CustomFieldManagerUnitTests.csproj new file mode 100644 index 0000000..6b0dae4 --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/e_suite.Modules.CusomFieldManagerUnitTest/e_suite.Modules.CustomFieldManagerUnitTests.csproj @@ -0,0 +1,32 @@ + + + + net10.0 + enable + enable + + false + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Modules.CustomFieldsManager/nuget.config b/e-suite.Modules.CustomFieldsManager/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.CustomFieldsManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/.gitattributes b/e-suite.Modules.DomainManager/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.DomainManager/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/.gitignore b/e-suite.Modules.DomainManager/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.DomainManager/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.DomainManager/.runsettings b/e-suite.Modules.DomainManager/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Modules.DomainManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/README.md b/e-suite.Modules.DomainManager/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.DomainManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/azure-pipelines.yml b/e-suite.Modules.DomainManager/azure-pipelines.yml new file mode 100644 index 0000000..2227604 --- /dev/null +++ b/e-suite.Modules.DomainManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + forceCoverageImprovement: true # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + #forceCoverageImprovement: false # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/CreateDomainAsyncUnitTests.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/CreateDomainAsyncUnitTests.cs new file mode 100644 index 0000000..9cc3a51 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/CreateDomainAsyncUnitTests.cs @@ -0,0 +1,205 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.DomainManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.DomainManager.UnitTests; + +[TestFixture] +public class CreateDomainAsyncUnitTests : DomainManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CreateDomainAsync_WhenDomainAlreadyExists_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("4c465763-f93f-4496-9f4b-4029cb2642c0"), + Id = 725, + Name = "The Hard Place", + Deleted = false + }; + + DomainManagerRepository.Domains.Add(domain); + + var createDomain = new CreateDomain + { + Guid = domain.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Domain already exists")); + } + + [Test] + public async Task CreateDomainAsync_WhenDeletedDomainExistsAndGuidProvided_DomainIsRestoredAndRenamed() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("4c465763-f93f-4496-9f4b-4029cb2642c0"), + Id = 725, + Name = "The Hard Place", + Deleted = true + }; + + DomainManagerRepository.Domains.Add(domain); + + var createDomain = new CreateDomain + { + Guid = domain.Guid, + Name = "The Hard Place Revisited" + }; + + //Act + await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None); + + //Assert + Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1)); + + Assert.That(domain.Guid, Is.EqualTo(createDomain.Guid)); + Assert.That(domain.Name, Is.EqualTo(createDomain.Name)); + Assert.That(domain.Id, Is.EqualTo(725)); + Assert.That(domain.Deleted, Is.False); + + Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.Null); + } + + [Test] + public async Task CreateDomainAsync_WhenDeletedDomainExistsAndNameOnlyProvided_DomainIsRestored() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("4c465763-f93f-4496-9f4b-4029cb2642c0"), + Id = 725, + Name = "The Hard Place", + Deleted = true + }; + + DomainManagerRepository.Domains.Add(domain); + + var createDomain = new CreateDomain + { + Name = domain.Name + }; + + //Act + await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None); + + //Assert + Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1)); + + Assert.That(domain.Id, Is.EqualTo(725)); + Assert.That(domain.Deleted, Is.False); + + Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.Null); + } + + [Test] + public async Task CreateDomainAsync_WhenDomainIsNew_GetsCreated() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var createDomain = new CreateDomain + { + Guid = new Guid("814758b1-d7a3-4708-96dd-338c5382c3f5"), + Name = "Trotters Independent Traders" + }; + + //Act + await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None); + + //Assert + Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1)); + + var domain = DomainManagerRepository.Domains.First(); + Assert.That(domain.Guid, Is.EqualTo(createDomain.Guid)); + Assert.That(domain.Name, Is.EqualTo(createDomain.Name)); + Assert.That(domain.SsoProvider, Is.Null); + + Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.EqualTo(domain)); + Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.Not.Null); + } + + [Test] + public async Task CreateDomainAsync_WhenDomainConsainsSsoProvider_GetsCreated() + { + //Arrange + var ssoProviderId = 1; + + SoManagerRepository.SsoProviders.Add( new SsoProvider + { + Id = ssoProviderId + }); + + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var createDomain = new CreateDomain + { + Guid = new Guid("814758b1-d7a3-4708-96dd-338c5382c3f5"), + Name = "Trotters Independent Traders", + SsoProviderId = new GeneralIdRef{ Id = ssoProviderId } + }; + + //Act + await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None); + + //Assert + Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1)); + + var domain = DomainManagerRepository.Domains.First(); + Assert.That(domain.SsoProvider, Is.Not.Null); + + + Assert.That(domain.SsoProvider?.Id, Is.EqualTo(ssoProviderId)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/DeleteDomainAsync.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/DeleteDomainAsync.cs new file mode 100644 index 0000000..6ddae01 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/DeleteDomainAsync.cs @@ -0,0 +1,114 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.DomainManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.DomainManager.UnitTests; + +[TestFixture] +public class DeleteDomainAsync: DomainManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteDomainAsync_DomainNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var deleteDomain = new GeneralIdRef + { + Guid = new Guid("55359f68-47f3-4b79-8bb2-e7a5e2f92cae") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await DomainManager.DeleteDomainAsync(auditUserDetails, deleteDomain, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Domain not found")); + } + + [Test] + public async Task DeleteDomainAsync_DomainNotDeleted_DomainGetsDeleted() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("8b7a3e33-9ab8-4c10-b0d5-8dbcade59569"), + Id = 777, + Name = "Delete me", + Deleted = false + }; + + DomainManagerRepository.Domains.Add(domain); + + var deleteDomain = new GeneralIdRef + { + Guid = domain.Guid + }; + + //Act + await DomainManager.DeleteDomainAsync(auditUserDetails, deleteDomain, CancellationToken.None); + + //Assert + Assert.That(domain.Deleted, Is.True); + } + + [Test] + public void DeleteDomainAsync_AttemptToDeleteSunDomain_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("3470d32f-8796-409d-8408-8121fe13b154"), + Id = 1, + Name = "Sun Branding Solutions", + Deleted = false + }; + + DomainManagerRepository.Domains.Add(domain); + + var deleteDomain = new GeneralIdRef + { + Guid = domain.Guid + }; + + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await DomainManager.DeleteDomainAsync(auditUserDetails, deleteDomain, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Not allowed to delete the Sun Branding Solutions domain")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/EditDomainAsync.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/EditDomainAsync.cs new file mode 100644 index 0000000..3441cb7 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/EditDomainAsync.cs @@ -0,0 +1,185 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.DomainManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.DomainManager.UnitTests; + +[TestFixture] +public class EditDomainAsync : DomainManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditDomainAsync_DomainNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var editDomain = new EditDomain + { + Id = new GeneralIdRef + { + Guid = new Guid("55359f68-47f3-4b79-8bb2-e7a5e2f92cae") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await DomainManager.EditDomainAsync(auditUserDetails, editDomain, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Domain not found")); + } + + [Test] + public async Task EditDomainAsync_DomainExists_DomainIsEditedProperly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("8b7a3e33-9ab8-4c10-b0d5-8dbcade59569"), + Id = 777, + Name = "Inglish Teetchers" + }; + + DomainManagerRepository.Domains.Add(domain); + + var editDomain = new EditDomain + { + Id = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = "English Teachers" + }; + + //Act + await DomainManager.EditDomainAsync(auditUserDetails, editDomain, CancellationToken.None); + + //Assert + Assert.That(domain.Name, Is.EqualTo("English Teachers")); + } + + [Test] + public async Task EditDomainAsync_SsoProviderIsNullAndGetsSet_DomainIsEditedProperly() + { + //Arrange + var ssoProviderId = 234; + + SoManagerRepository.SsoProviders.Add(new SsoProvider + { + Id = ssoProviderId + }); + + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("8b7a3e33-9ab8-4c10-b0d5-8dbcade59569"), + Id = 777, + Name = "English Teachers", + SsoProviderId = null, + SsoProvider = null + }; + + DomainManagerRepository.Domains.Add(domain); + + var editDomain = new EditDomain + { + Id = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = "English Teachers", + SsoProviderId = new GeneralIdRef{Id = ssoProviderId} + }; + + //Act + await DomainManager.EditDomainAsync(auditUserDetails, editDomain, CancellationToken.None); + + //Assert + Assert.That(domain.SsoProviderId, Is.EqualTo(ssoProviderId)); + Assert.That(domain.SsoProvider, Is.Not.Null); + } + + [Test] + public async Task EditDomainAsync_SsoProviderIsChanged_DomainIsEditedProperly() + { + //Arrange + var originalSsoProvider = new SsoProvider + { + Id = 234 + }; + + var changedSsoProvider = new SsoProvider + { + Id = 345 + }; + + SoManagerRepository.SsoProviders.Add(originalSsoProvider); + SoManagerRepository.SsoProviders.Add(changedSsoProvider); + + var auditUserDetails = new AuditUserDetails + { + UserId = 100, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var domain = new Domain + { + Guid = new Guid("8b7a3e33-9ab8-4c10-b0d5-8dbcade59569"), + Id = 777, + Name = "English Teachers", + SsoProviderId = originalSsoProvider.Id, + SsoProvider = null + }; + + DomainManagerRepository.Domains.Add(domain); + + var editDomain = new EditDomain + { + Id = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = "English Teachers", + SsoProviderId = new GeneralIdRef { Id = changedSsoProvider.Id } + }; + + //Act + await DomainManager.EditDomainAsync(auditUserDetails, editDomain, CancellationToken.None); + + //Assert + Assert.That(domain.SsoProviderId, Is.EqualTo(changedSsoProvider.Id)); + Assert.That(domain.SsoProvider, Is.EqualTo(changedSsoProvider)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/GetDomainAsyncUnitTests.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/GetDomainAsyncUnitTests.cs new file mode 100644 index 0000000..d1af21f --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/GetDomainAsyncUnitTests.cs @@ -0,0 +1,62 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.DomainManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.DomainManager.UnitTests; + +[TestFixture] +public class GetDomainAsyncUnitTests : DomainManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetDomainAsync_DomainNotExisting_ThrowsNotFoundException() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("8d5c8114-ad04-492c-a5d3-271584763126") + }; + + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var result = await DomainManager.GetDomainAsync(generalIdRef, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Domain not found")); + } + + [Test] + public async Task GetDomainAsync_WhenDomainFound_ReturnsDomain() + { + //Arrange + var domain = new Domain + { + Guid = new Guid("a618a2a8-ea9f-403b-9730-cc73ba12d8b3"), + Name = "Testing domain" + }; + + DomainManagerRepository.Domains.Add(domain); + + var generalIdRef = new GeneralIdRef + { + Guid = domain.Guid, + }; + + //Act + var result = await DomainManager.GetDomainAsync(generalIdRef, CancellationToken.None); + + //Assert + Assert.That( result, Is.Not.Null); + Assert.That( result.Guid, Is.EqualTo(domain.Guid)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/GetDomainsAsyncUnitTests.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/GetDomainsAsyncUnitTests.cs new file mode 100644 index 0000000..be36e04 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/GetDomainsAsyncUnitTests.cs @@ -0,0 +1,86 @@ +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.DomainManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.DomainManager.UnitTests; + +[TestFixture] +public class GetDomainsAsyncUnitTests : DomainManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetDomainsAsync_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var paging = new Paging(); + + var testDomain1 = new Domain + { + Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"), + Id = 1, + Name = "Test Domain 1" + }; + + DomainManagerRepository.Domains.Add(testDomain1); + + //Act + var result = await DomainManager.GetDomainsAsync(paging, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + + var firstDomain = result.Data.First(); + Assert.That(firstDomain.Guid, Is.EqualTo(testDomain1.Guid)); + Assert.That(firstDomain.Id, Is.EqualTo(testDomain1.Id)); + Assert.That(firstDomain.Name, Is.EqualTo(testDomain1.Name)); + Assert.That(firstDomain.SsoProviderId, Is.Null); + } + + [Test] + public async Task GetDomainsAsync_WhenDomainHasSsoProviderId_ReturnsSsoProviderId() + { + //Arrange + var ssoProviderId = 1; + var ssoProviderGuid = new Guid("49A2F070-7455-4C1C-9E57-C8E0E2527DD6"); + + var paging = new Paging(); + + var testDomain1 = new Domain + { + Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"), + Id = 1, + Name = "Test Domain 1", + SsoProviderId = ssoProviderId, + SsoProvider = new SsoProvider + { + Id = 1, + Guid = ssoProviderGuid, + Name = "Test Provider" + } + }; + + DomainManagerRepository.Domains.Add(testDomain1); + + //Act + var result = await DomainManager.GetDomainsAsync(paging, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + + var firstDomain = result.Data.First(); + Assert.That(firstDomain.SsoProviderId, Is.Not.Null); + Assert.That(firstDomain.SsoProviderId?.Id, Is.EqualTo(ssoProviderId)); + Assert.That(firstDomain.SsoProviderId?.Guid, Is.EqualTo(ssoProviderGuid)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/DomainManagerTestBase.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/DomainManagerTestBase.cs new file mode 100644 index 0000000..e645f5d --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/DomainManagerTestBase.cs @@ -0,0 +1,21 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; + +namespace e_suite.Modules.DomainManager.UnitTests.Helpers; + +public class DomainManagerTestBase : TestBase +{ + protected FakeDomainRepository DomainManagerRepository = null!; + protected FakeSsoManagerRepository SoManagerRepository = null!; + protected IDomainManager DomainManager = null!; + + public override async Task Setup() + { + await base.Setup(); + + DomainManagerRepository = new FakeDomainRepository(); + SoManagerRepository = new FakeSsoManagerRepository(); + + DomainManager = new DomainManager(DomainManagerRepository, SoManagerRepository); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/FakeDomainRepository.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/FakeDomainRepository.cs new file mode 100644 index 0000000..40aab53 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/FakeDomainRepository.cs @@ -0,0 +1,50 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace e_suite.Modules.DomainManager.UnitTests.Helpers; + +public class FakeDomainRepository : FakeRepository, IDomainRepository +{ + public List Domains = new(); + public Domain? AddAdministratorRoleCalled = null; + public Domain? EditDomainCalled = null; + + + public IQueryable GetDomains() + { + return Domains.BuildMock(); + } + + public Task GetDomainById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(GetDomains().FindByGeneralIdRef(generalIdRef)); + } + + public Task GetDomainByName(string domainName, CancellationToken cancellationToken) + { + return Task.FromResult(GetDomains().SingleOrDefault(x => x.Name == domainName)); + } + + public Task EditDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + EditDomainCalled = domain; + return Task.CompletedTask; + } + + public Task CreateDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + Domains.Add(domain); + return Task.CompletedTask; + } + + public Task AddAdministratorRoleAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + AddAdministratorRoleCalled = domain; + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/FakeSsoManagerRepository.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/FakeSsoManagerRepository.cs new file mode 100644 index 0000000..c19816a --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/Helpers/FakeSsoManagerRepository.cs @@ -0,0 +1,42 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace e_suite.Modules.DomainManager.UnitTests.Helpers; + +public class FakeSsoManagerRepository : FakeRepository, ISsoManagerRepository +{ + public List SsoProviders = new List(); + + public IQueryable GetSsoProviders() + { + return SsoProviders.BuildMock(); + } + + public Task GetSsoProviderAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(GetSsoProviders().FindByGeneralIdRef(generalIdRef)); + } + + public Task CreateNewSsoProviderAsync( + AuditUserDetails auditUserDetails, + SsoProvider newSsoProvider, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task EditNewSsoProviderAsync( + AuditUserDetails auditUserDetails, + SsoProvider ssoProvider, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/e-suite.Modules.DomainManager.UnitTests.csproj b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/e-suite.Modules.DomainManager.UnitTests.csproj new file mode 100644 index 0000000..f45338b --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.UnitTests/e-suite.Modules.DomainManager.UnitTests.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + e_suite.Modules.DomainManager.UnitTests + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.sln b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.sln new file mode 100644 index 0000000..820174a --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.DomainManager", "e-suite.Modules.DomainManager\e-suite.Modules.DomainManager.csproj", "{8280B724-FFF2-4497-916D-68710DBF9EA6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{7BAADD58-05CD-4821-862C-7A8291D25E42}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0AE084D2-2A38-4459-AB90-BC01D9DFE440}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.DomainManager.UnitTests", "e-suite.Modules.DomainManager.UnitTests\e-suite.Modules.DomainManager.UnitTests.csproj", "{B7D56894-B5D7-4DA1-8C0A-B6D513E49AE4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8280B724-FFF2-4497-916D-68710DBF9EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8280B724-FFF2-4497-916D-68710DBF9EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8280B724-FFF2-4497-916D-68710DBF9EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8280B724-FFF2-4497-916D-68710DBF9EA6}.Release|Any CPU.Build.0 = Release|Any CPU + {B7D56894-B5D7-4DA1-8C0A-B6D513E49AE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7D56894-B5D7-4DA1-8C0A-B6D513E49AE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7D56894-B5D7-4DA1-8C0A-B6D513E49AE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7D56894-B5D7-4DA1-8C0A-B6D513E49AE4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0AE084D2-2A38-4459-AB90-BC01D9DFE440} = {7BAADD58-05CD-4821-862C-7A8291D25E42} + {B7D56894-B5D7-4DA1-8C0A-B6D513E49AE4} = {0AE084D2-2A38-4459-AB90-BC01D9DFE440} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B9D01D74-238E-4E19-A4D7-A928076CFCC5} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/DomainManager.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/DomainManager.cs new file mode 100644 index 0000000..f097466 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/DomainManager.cs @@ -0,0 +1,182 @@ +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; + +namespace e_suite.Modules.DomainManager +{ + public class DomainManager : IDomainManager + { + private readonly IDomainRepository _domainRepository; + private readonly ISsoManagerRepository _ssoManagerRepository; + + public DomainManager(IDomainRepository domainRepository, ISsoManagerRepository soManagerRepository) + { + _domainRepository = domainRepository; + _ssoManagerRepository = soManagerRepository; + } + + public async Task> GetDomainsAsync(Paging paging, CancellationToken cancellationToken) + { + var forms = _domainRepository.GetDomains(); + + var paginatedData = await PaginatedData.Paginate(forms, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(MapDomain) + }; + return paginatedResult; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "name" => x => x.Name.Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "name" => x => x.Name, + _ => x => x.Name + }; + } + + private static GetDomain MapDomain(Domain domain) + { + return new GetDomain + { + Guid = domain.Guid, + Id = domain.Id, + Name = domain.Name, + SsoProviderId = domain.SsoProvider?.ToGeneralIdRef(), + SunriseHostName = domain.SunriseHostname, + SunriseAppId = domain.SunriseAppId, + SunriseCategoryId = domain.SunriseCategoryId, + SigmaId = domain.SigmaId, + }; + } + + public async Task GetDomainAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var domain = await _domainRepository.GetDomainById(generalIdRef, cancellationToken); + AssertDomain(domain); + return MapDomain(domain!); + } + + public async Task CreateDomainAsync(AuditUserDetails auditUserDetails, CreateDomain createDomain, + CancellationToken cancellationToken) + { + await _domainRepository.TransactionAsync(async () => + { + Domain? domain = null; + if (createDomain.Guid != null) + { + domain = await _domainRepository.GetDomainById(new GeneralIdRef { Guid = createDomain.Guid }, + cancellationToken); + } + + domain ??= await _domainRepository.GetDomainByName(createDomain.Name, cancellationToken); + + domain = domain switch + { + { Deleted: false } => throw new ExistsException("Domain already exists"), + null => new Domain { Guid = createDomain.Guid ?? Guid.NewGuid() }, + _ => domain + }; + + domain.Name = createDomain.Name; + domain.SunriseHostname = createDomain.SunriseHostName; + domain.SunriseAppId = createDomain.SunriseAppId; + domain.SunriseCategoryId = createDomain.SunriseCategoryId; + domain.SigmaId = createDomain.SigmaId; + + if (createDomain.SsoProviderId != null) + { + var ssoProvider = + await _ssoManagerRepository.GetSsoProviderAsync(createDomain.SsoProviderId, cancellationToken); + domain.SsoProviderId = ssoProvider?.Id; + domain.SsoProvider = ssoProvider; + } + + if (!domain.Deleted) + { + await _domainRepository.CreateDomainAsync(auditUserDetails, domain, cancellationToken); + + domain = await _domainRepository.GetDomainById(new GeneralIdRef { Guid = domain.Guid }, cancellationToken); + await _domainRepository.AddAdministratorRoleAsync(auditUserDetails, domain!, cancellationToken); + } + else + { + domain.Deleted = false; + await _domainRepository.EditDomainAsync(auditUserDetails, domain, cancellationToken); + } + }); + } + private static void AssertDomain(Domain? customField) + { + if (customField == null || customField.Deleted) + { + throw new NotFoundException($"Domain not found"); + } + } + + public async Task EditDomainAsync(AuditUserDetails auditUserDetails, EditDomain editDomain, CancellationToken cancellationToken) + { + await _domainRepository.TransactionAsync(async () => + { + var domain = await _domainRepository.GetDomainById(editDomain.Id, cancellationToken); + AssertDomain(domain); + domain!.Name = editDomain.Name; + + var ssoProvider = editDomain.SsoProviderId != null + ? await _ssoManagerRepository.GetSsoProviderAsync(editDomain.SsoProviderId, cancellationToken) + : null; + + domain.SsoProviderId = ssoProvider?.Id; + domain.SsoProvider = ssoProvider; + domain.SunriseHostname = editDomain.SunriseHostName; + domain.SunriseAppId = editDomain.SunriseAppId; + domain.SunriseCategoryId = editDomain.SunriseCategoryId; + domain.SigmaId = editDomain.SigmaId; + + await _domainRepository.EditDomainAsync(auditUserDetails, domain, cancellationToken); + }); + } + + public async Task DeleteDomainAsync(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, + CancellationToken cancellationToken) + { + await _domainRepository.TransactionAsync(async () => + { + var domain = await _domainRepository.GetDomainById(generalIdRef, cancellationToken); + AssertDomain(domain); + + if (domain!.Id == 1) + throw new InvalidOperationException($"Not allowed to delete the {domain.Name} domain"); + + domain!.Deleted = true; + await _domainRepository.EditDomainAsync(auditUserDetails, domain, cancellationToken); + }); + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/GlobalSuppressions.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/IocRegistration.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/IocRegistration.cs new file mode 100644 index 0000000..fff7f5d --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.DomainManager.Repository; + +namespace e_suite.Modules.DomainManager; + +public class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/Repository/DomainRepository.cs b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/Repository/DomainRepository.cs new file mode 100644 index 0000000..6fb0072 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/Repository/DomainRepository.cs @@ -0,0 +1,63 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.DomainManager.Repository; + +public class DomainRepository : RepositoryBase, IDomainRepository +{ + public DomainRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetDomains() + { + return DatabaseDbContext.Domains.Where(x => !x.Deleted); + } + + public async Task GetDomainById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Domains + .Include(nameof(Domain.SsoProvider)) + .FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task GetDomainByName(string domainName, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Domains.SingleOrDefaultAsync(x => x.Name == domainName, cancellationToken); + } + + public async Task EditDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + DatabaseDbContext.Domains.Update(domain); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task CreateDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + await DatabaseDbContext.Domains.AddAsync(domain, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task AddAdministratorRoleAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + var administratorRole = new Role + { + Name = "Administrators", + Domain = domain, + IsSuperUser = false, + IsAdministrator = true, + CanDelete = false, + Deleted = false, + Guid = Guid.NewGuid(), + }; + + await DatabaseDbContext.Roles.AddAsync(administratorRole, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.csproj b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.csproj new file mode 100644 index 0000000..8ab8bb5 --- /dev/null +++ b/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager/e-suite.Modules.DomainManager.csproj @@ -0,0 +1,17 @@ + + + + net10.0 + e_suite.Modules.DomainManager + enable + enable + + + + + + + + + + diff --git a/e-suite.Modules.DomainManager/nuget.config b/e-suite.Modules.DomainManager/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.DomainManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ExceptionLogManager/.gitattributes b/e-suite.Modules.ExceptionLogManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.ExceptionLogManager/.gitignore b/e-suite.Modules.ExceptionLogManager/.gitignore new file mode 100644 index 0000000..27387bf --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/.gitignore @@ -0,0 +1,367 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +#NCrunch +*.ncrunchsoltuon +*.ncrunchsolution diff --git a/e-suite.Modules.ExceptionLogManager/.runsettings b/e-suite.Modules.ExceptionLogManager/.runsettings new file mode 100644 index 0000000..a43367b --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/.runsettings @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + .*microsoft.testplatform.* + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.ExceptionLogManager/README.md b/e-suite.Modules.ExceptionLogManager/README.md new file mode 100644 index 0000000..5305ed0 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/README.md @@ -0,0 +1 @@ +# e-suite.Modules.ExceptionLogManager \ No newline at end of file diff --git a/e-suite.Modules.ExceptionLogManager/azure-pipelines.yml b/e-suite.Modules.ExceptionLogManager/azure-pipelines.yml new file mode 100644 index 0000000..c962b96 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/azure-pipelines.yml @@ -0,0 +1,133 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '70' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/ExtensionUnitTests.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/ExtensionUnitTests.cs new file mode 100644 index 0000000..175679c --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/ExtensionUnitTests.cs @@ -0,0 +1,38 @@ +using e_suite.Modules.ExceptionLogManager.Extensions; +using e_suite.Modules.ExceptionLogManager.UnitTests.Helpers; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace e_suite.Modules.ExceptionLogManager.UnitTests; + +public class ExtensionUnitTests: ExceptionLogManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DoubleExtensionMethod_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var ex = new NullReferenceException(); + var exception = new Database.Core.Tables.Diagnostics.ExceptionLog + { + Application = "E-Suite API", + Message = "Internal Server Error", + StackTrace = ex.StackTrace ?? string.Empty, + ExceptionJson = JsonConvert.SerializeObject(ex), + SupportingData = string.Empty, + OccuredAt = _fakeClock.GetNow + }; + + //Act + var result = exception.ToExceptionLog(); + + //Assert + Assert.That(result.GetType().Name, Is.EqualTo("ExceptionLog")); + Assert.Pass(); + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/GetExceptionLogsUnitTests.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/GetExceptionLogsUnitTests.cs new file mode 100644 index 0000000..3a19e52 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/GetExceptionLogsUnitTests.cs @@ -0,0 +1,40 @@ +using e_suite.Modules.ExceptionLogManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.ExceptionLogManager.UnitTests; + +public class GetExceptionLogsUnitTests: ExceptionLogManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetLogException_WhenCalled_UsingRespository_ReturnsExpectedResult() + { + //Act + await ExceptionLogManager.LogException(new DivideByZeroException(), "Unit Test", string.Empty, CancellationToken.None); + var result = ExceptionLogManagerRepository.GetExceptionLogs(); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.Pass(); + } + + [Test] + public async Task GetLogException_WhenCalled_UsingLogger_ReturnsExpectedResult() + { + //Act + await ExceptionLogManager.LogException(new DivideByZeroException(), "Unit Test", string.Empty, CancellationToken.None); + var result = ExceptionLogManager.GetExceptionLogs(new Paging(), CancellationToken.None).Result; + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.Pass(); + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/Helpers/ExceptionLogManagerTestBase.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/Helpers/ExceptionLogManagerTestBase.cs new file mode 100644 index 0000000..f7b5736 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/Helpers/ExceptionLogManagerTestBase.cs @@ -0,0 +1,19 @@ +using e_suite.API.Common; +using e_suite.Modules.ExceptionLogManager.UnitTests.Repository; +using e_suite.UnitTestCore; + +namespace e_suite.Modules.ExceptionLogManager.UnitTests.Helpers; + +public class ExceptionLogManagerTestBase: TestBase +{ + protected FakeExceptionLogManagerRepository ExceptionLogManagerRepository { get; set; } = null!; + protected IExceptionLogManager ExceptionLogManager { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + ExceptionLogManagerRepository = new FakeExceptionLogManagerRepository(); + + ExceptionLogManager = new ExceptionLogger(_fakeClock, ExceptionLogManagerRepository); + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/LogExceptionUnitTests.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/LogExceptionUnitTests.cs new file mode 100644 index 0000000..537147b --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/LogExceptionUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.Modules.ExceptionLogManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.ExceptionLogManager.UnitTests +{ + public class LogExceptionUnitTests: ExceptionLogManagerTestBase + { + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LogException_WhenCalled_UsingRespository_ReturnsExpectedResult() + { + //Act + await ExceptionLogManager.LogException(new DivideByZeroException(), "Unit Test", string.Empty, CancellationToken.None); + var result = ExceptionLogManagerRepository.GetExceptionLogs(); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.Pass(); + } + + [Test] + public async Task LogException_WhenCalled_UsingLogger_ReturnsExpectedResult() + { + //Act + await ExceptionLogManager.LogException(new DivideByZeroException(), "Unit Test", string.Empty, CancellationToken.None); + var result = await ExceptionLogManager.GetExceptionLogs(new Paging(), CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(1)); + Assert.Pass(); + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/Repository/FakeExceptionLogManagerRepository.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/Repository/FakeExceptionLogManagerRepository.cs new file mode 100644 index 0000000..dab381f --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/Repository/FakeExceptionLogManagerRepository.cs @@ -0,0 +1,21 @@ +using e_suite.API.Common.repository; +using e_suite.UnitTestCore; +using MockQueryable; + +namespace e_suite.Modules.ExceptionLogManager.UnitTests.Repository; + +public class FakeExceptionLogManagerRepository : FakeRepository, IExceptionLogRepository +{ + public List ExceptionLogs = []; + + public IQueryable GetExceptionLogs() + { + return ExceptionLogs.BuildMock(); + } + + public Task LogException(Database.Core.Tables.Diagnostics.ExceptionLog exception, CancellationToken cancellationToken) + { + ExceptionLogs.Add(exception); + return Task.FromResult(exception.Id); + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/e-suite.Modules.ExceptionLogManager.UnitTests.csproj b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/e-suite.Modules.ExceptionLogManager.UnitTests.csproj new file mode 100644 index 0000000..3c4e2c9 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.UnitTests/e-suite.Modules.ExceptionLogManager.UnitTests.csproj @@ -0,0 +1,32 @@ + + + + net10.0 + e_suite.Modules.ExceptionLogManager.UnitTests + enable + enable + + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.sln b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.sln new file mode 100644 index 0000000..5088e5c --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33829.357 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.ExceptionLogManager", "e-suite.Modules.ExceptionLogManager\e-suite.Modules.ExceptionLogManager.csproj", "{A073FC29-A956-4C3E-A9BB-4885335FA6AA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{5DF5575F-790E-4D35-ABD1-D5A05A549B83}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0CBB9412-D539-4481-A1DD-06757730C66F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Modules.ExceptionLogManager.UnitTests", "e-suite.Modules.ExceptionLogManager.UnitTests\e-suite.Modules.ExceptionLogManager.UnitTests.csproj", "{B837B89B-3B88-4CAB-AF26-CD5D16E45C4C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A073FC29-A956-4C3E-A9BB-4885335FA6AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A073FC29-A956-4C3E-A9BB-4885335FA6AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A073FC29-A956-4C3E-A9BB-4885335FA6AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A073FC29-A956-4C3E-A9BB-4885335FA6AA}.Release|Any CPU.Build.0 = Release|Any CPU + {B837B89B-3B88-4CAB-AF26-CD5D16E45C4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B837B89B-3B88-4CAB-AF26-CD5D16E45C4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B837B89B-3B88-4CAB-AF26-CD5D16E45C4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B837B89B-3B88-4CAB-AF26-CD5D16E45C4C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0CBB9412-D539-4481-A1DD-06757730C66F} = {5DF5575F-790E-4D35-ABD1-D5A05A549B83} + {B837B89B-3B88-4CAB-AF26-CD5D16E45C4C} = {0CBB9412-D539-4481-A1DD-06757730C66F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2C23A037-2142-466E-A2E7-12453EA59C92} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/ExceptionLogger.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/ExceptionLogger.cs new file mode 100644 index 0000000..26dbd3d --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/ExceptionLogger.cs @@ -0,0 +1,87 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Modules.ExceptionLogManager.Extensions; +using e_suite.Utilities.Pagination; +using eSuite.Core.Clock; +using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; + +namespace e_suite.Modules.ExceptionLogManager; + +public class ExceptionLogger : IExceptionLogManager +{ + private readonly IClock _clock; + private readonly IExceptionLogRepository _exceptionLogRepository; + + public ExceptionLogger(IClock clock, IExceptionLogRepository exceptionLogRepository) + { + _clock = clock; + _exceptionLogRepository = exceptionLogRepository; + } + + public async Task> GetExceptionLogs(Paging paging, CancellationToken cancellationToken) + { + var exceptionLogs = _exceptionLogRepository.GetExceptionLogs(); + + var paginatedData = await PaginatedData.Paginate(exceptionLogs, paging, + KeySelector, FilterSelector, cancellationToken); + + return new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(x => x.ToExceptionLog()) + }; + } + + [ExcludeFromCodeCoverage] + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "application" => x => x.Application.ToString().Contains(value), + "exceptionJson" => x => x.ExceptionJson.ToString().Contains(value), + "message" => x => x.Message.ToString().Contains(value), + "stackTrace" => x => x.StackTrace.ToString().Contains(value), + "supportingData" => x => x.SupportingData.ToString().Contains(value), + "occuredAt" => x => x.OccuredAt.ToString().Contains(value), + _ => x => x.Id.ToString().Contains(value) + }; + } + + [ExcludeFromCodeCoverage] + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "application" => x => x.Application, + "exceptionJson" => x => x.ExceptionJson, + "message" => x => x.Message, + "stackTrace" => x => x.StackTrace, + "supportingData" => x => x.SupportingData, + "occuredAt" => x => x.OccuredAt, + _ => x => x.Id + }; + } + + public async Task LogException(Exception ex, string application, string supportingArgs, CancellationToken cancellationToken) + { + var exceptionLog = new Database.Core.Tables.Diagnostics.ExceptionLog + { + Application = application, + Message = ex.Message, + StackTrace = ex.StackTrace ?? string.Empty, + ExceptionJson = JsonConvert.SerializeObject(ex), + SupportingData = supportingArgs, + OccuredAt = _clock.GetNow + }; + + var exceptionId = await _exceptionLogRepository.LogException(exceptionLog, cancellationToken); + return exceptionId; + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/Extensions/ExceptionLogExtension.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/Extensions/ExceptionLogExtension.cs new file mode 100644 index 0000000..d520291 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/Extensions/ExceptionLogExtension.cs @@ -0,0 +1,20 @@ +using e_suite.API.Common.models; + +namespace e_suite.Modules.ExceptionLogManager.Extensions; + +public static class ExceptionLogExtension +{ + public static ExceptionLog ToExceptionLog(this Database.Core.Tables.Diagnostics.ExceptionLog exceptionLog) + { + return new ExceptionLog + { + Id = exceptionLog.Id, + Application = exceptionLog.Application, + ExceptionJson = exceptionLog.ExceptionJson, + Message = exceptionLog.Message, + OccuredAt = exceptionLog.OccuredAt, + StackTrace = exceptionLog.StackTrace, + SupportingData = exceptionLog.SupportingData + }; + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/IocRegistration.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/IocRegistration.cs new file mode 100644 index 0000000..346df50 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.ExceptionLogManager.Repository; + +namespace e_suite.Modules.ExceptionLogManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/Repository/ExceptionLogRepository.cs b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/Repository/ExceptionLogRepository.cs new file mode 100644 index 0000000..8e7bc11 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/Repository/ExceptionLogRepository.cs @@ -0,0 +1,23 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core; + +namespace e_suite.Modules.ExceptionLogManager.Repository; + +public class ExceptionLogRepository : RepositoryBase, IExceptionLogRepository +{ + public ExceptionLogRepository(IEsuiteDatabaseDbContext esuiteDatabaseDbContext) : base(esuiteDatabaseDbContext) + { + } + + public IQueryable GetExceptionLogs() + { + return DatabaseDbContext.ExceptionLogs; + } + + public async Task LogException(Database.Core.Tables.Diagnostics.ExceptionLog exception, CancellationToken cancellationToken) + { + await DatabaseDbContext.ExceptionLogs.AddAsync(exception, cancellationToken); + await DatabaseDbContext.NoAuditSaveChangesAsync(cancellationToken); + return exception.Id; + } +} diff --git a/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.csproj b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.csproj new file mode 100644 index 0000000..a7fbf6b --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager/e-suite.Modules.ExceptionLogManager.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + e_suite.Modules.ExceptionLogManager + enable + enable + + + + + + + + + + + diff --git a/e-suite.Modules.ExceptionLogManager/nuget.config b/e-suite.Modules.ExceptionLogManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.ExceptionLogManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/.gitattributes b/e-suite.Modules.FormsManager/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.FormsManager/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/.gitignore b/e-suite.Modules.FormsManager/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.FormsManager/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.FormsManager/.runsettings b/e-suite.Modules.FormsManager/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Modules.FormsManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/README.md b/e-suite.Modules.FormsManager/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.FormsManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/azure-pipelinse.yml b/e-suite.Modules.FormsManager/azure-pipelinse.yml new file mode 100644 index 0000000..39745c6 --- /dev/null +++ b/e-suite.Modules.FormsManager/azure-pipelinse.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.sln b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.sln new file mode 100644 index 0000000..fa06b9b --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.FormsManager", "e-suite.Modules.FormsManager\e-suite.Modules.FormsManager.csproj", "{A603D4AB-AA96-4DD7-B81A-2BFF94055A84}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e_suite.Modules.FormsManagerUnitTests", "e_suite.Modules.Form.ManagerUnitTest\e_suite.Modules.FormsManagerUnitTests.csproj", "{39475B15-DEA9-458A-81AC-ABDE57BEAE74}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{0F0C055B-522F-40C1-B788-784BD6C267AA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{43417A3B-3F8E-42F2-8B0F-548EFCFEBEBF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A603D4AB-AA96-4DD7-B81A-2BFF94055A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A603D4AB-AA96-4DD7-B81A-2BFF94055A84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A603D4AB-AA96-4DD7-B81A-2BFF94055A84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A603D4AB-AA96-4DD7-B81A-2BFF94055A84}.Release|Any CPU.Build.0 = Release|Any CPU + {39475B15-DEA9-458A-81AC-ABDE57BEAE74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39475B15-DEA9-458A-81AC-ABDE57BEAE74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39475B15-DEA9-458A-81AC-ABDE57BEAE74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39475B15-DEA9-458A-81AC-ABDE57BEAE74}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {39475B15-DEA9-458A-81AC-ABDE57BEAE74} = {43417A3B-3F8E-42F2-8B0F-548EFCFEBEBF} + {43417A3B-3F8E-42F2-8B0F-548EFCFEBEBF} = {0F0C055B-522F-40C1-B788-784BD6C267AA} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4CE53FA5-3CC1-4A72-9891-93D31A088EB4} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/FormFieldValueKeyComparer.cs b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/FormFieldValueKeyComparer.cs new file mode 100644 index 0000000..415f45f --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/FormFieldValueKeyComparer.cs @@ -0,0 +1,19 @@ +using e_suite.Database.Core.Tables.Forms; + +namespace e_suite.Modules.FormsManager; + +public class FormFieldValueKeyComparer : IComparer +{ + public int Compare(FormFieldInstance? x, FormFieldInstance? y) + { + if (ReferenceEquals(x, y)) return 0; + if (y is null) return 1; + if (x is null) return -1; + + var idComparison = x.FormInstanceId.CompareTo(y.FormInstanceId); + if (idComparison != 0) return idComparison; + var customFieldIdComparison = x.CustomFieldId.CompareTo(y.CustomFieldId); + if (customFieldIdComparison != 0) return customFieldIdComparison; + return x.Index.CompareTo(y.Index); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/FormsManager.cs b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/FormsManager.cs new file mode 100644 index 0000000..7d732b7 --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/FormsManager.cs @@ -0,0 +1,526 @@ +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using HtmlAgilityPack; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.FormsManager; + +public class FormsManager : IFormsManager +{ + private readonly IFormRepository _formRepository; + private readonly ICustomFieldRepository _customFieldRepository; + private readonly ICustomFieldHelper _customFieldHelper; + private readonly ICustomFieldValidator _customFieldValidator; + + public FormsManager(IFormRepository formRepository, ICustomFieldRepository customFieldRepository, ICustomFieldHelper customFieldHelper, ICustomFieldValidator customFieldValidator) + { + _formRepository = formRepository; + _customFieldRepository = customFieldRepository; + _customFieldHelper = customFieldHelper; + _customFieldValidator = customFieldValidator; + } + + private readonly Dictionary _currentFormTemplateVersionCache = []; + + + private static void Assert(FormTemplate? customField) + { + if (customField == null || customField.Deleted) + { + throw new NotFoundException($"There is no CustomField with this Id"); + } + } + + public async Task CreateFormTemplateAsync(AuditUserDetails auditUserDetails, CreateFormTemplate createFormTemplate, CancellationToken cancellationToken) + { + await _formRepository.TransactionAsync(async () => + { + + if (createFormTemplate.Guid != null && await _formRepository.GetTemplateAsync(new GeneralIdRef { Guid = createFormTemplate.Guid }, cancellationToken) != null) + throw new ExistsException("A Field with this id exists"); + + var formTemplate = new FormTemplate + { + Name = createFormTemplate.Name, + Guid = createFormTemplate.Guid ?? Guid.NewGuid() + }; + + await _formRepository.CreateTemplateAsync(auditUserDetails, formTemplate, cancellationToken); + Assert(formTemplate); + + var formVersion = new FormTemplateVersion + { + Version = 1, + FormDefinition = createFormTemplate.Definition, + TemplateId = formTemplate.Id, + Guid = Guid.NewGuid() + }; + + await _formRepository.CreateNewFormVersionAsync(auditUserDetails, formVersion, cancellationToken); + }); + } + + public async Task DeleteFormTemplateAsync(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + await _formRepository.TransactionAsync(async () => + { + var formTemplate = await _formRepository.GetTemplateWithOutLoadedRefereranceAsync(generalIdRef, cancellationToken) ?? throw new NotFoundException("Form with this id doesn't exists"); + formTemplate.Deleted = true; + await _formRepository.EditFormTemplateAsync(auditUserDetails, formTemplate, cancellationToken); + var formVersions = await _formRepository.GetAllFormVersions(formTemplate.Id).ToListAsync(cancellationToken); + await _formRepository.DeleteAllVersionsAsync(auditUserDetails, formVersions, cancellationToken); + }); + } + + public async Task EditFormTemplateAsync(AuditUserDetails auditUserDetails, EditFormTemplate formTemplate, CancellationToken cancellationToken) + { + await _formRepository.TransactionAsync(async () => + { + var formTemplateOriginal = await LoadAndEditFormTemplate(auditUserDetails, formTemplate, cancellationToken); + + var formVersions = await _formRepository.GetAllFormVersions(formTemplateOriginal.Id).ToListAsync(cancellationToken); + var lastFormVersion = formVersions.Last(); + if (lastFormVersion.FormDefinition != formTemplate.Definition) + { + var formVersion = new FormTemplateVersion + { + FormDefinition = formTemplate.Definition, + TemplateId = formTemplateOriginal.Id, + Version = lastFormVersion.Version + 1 + + }; + await _formRepository.CreateNewFormVersionAsync(auditUserDetails, formVersion, cancellationToken); + } + }); + } + + private async Task LoadAndEditFormTemplate(AuditUserDetails auditUserDetails, EditFormTemplate formTemplate, CancellationToken cancellationToken) + { + var formTemplateOriginal = await _formRepository.GetTemplateAsync(formTemplate.Id, cancellationToken); + Assert(formTemplateOriginal); + var editedFormTemplate = false; + if (!formTemplateOriginal!.Name.Equals(formTemplate.Name, StringComparison.InvariantCulture)) + { + editedFormTemplate = true; + formTemplateOriginal!.Name = formTemplate.Name; + } + + if (editedFormTemplate) + { + await _formRepository.EditFormTemplateAsync(auditUserDetails, formTemplateOriginal, cancellationToken); + } + + return formTemplateOriginal; + } + + public async Task GetFormTemplateAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var formTemplate = await _formRepository.GetTemplateAsync(generalIdRef, cancellationToken); + Assert(formTemplate); + return await MapFormTemplate(formTemplate!, cancellationToken); + } + + public async Task> GetFormTemplatesAsync(Paging paging, CancellationToken cancellationToken) + { + var forms = _formRepository.GetTemplates(); + + var paginatedData = await PaginatedData.Paginate(forms, paging, + KeySelector, FilterSelector, cancellationToken); + + + var mappedData = new List(); + + foreach (var item in paginatedData.Data) + mappedData.Add(await MapFormTemplate(item, cancellationToken)); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = mappedData + }; + return paginatedResult; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "version" => x => x.Versions.OrderByDescending(x => x.Version).First( v => v.Deleted == false).Version.ToString().Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "version" => x => x.Versions.OrderByDescending(x=>x.Version).First(x => !x.Deleted).Version, + _ => x => x.Name + }; + } + + private async Task MapFormTemplate(FormTemplate formTemplate, CancellationToken cancellationToken) + { + var currentVersion = await GetCurrentVersionFromTemplate(formTemplate, cancellationToken); + + var fieldsAsGeneralIdRefs = await GetCustomFieldsFromDefinition(currentVersion.FormDefinition); + var customFieldDefinitions = await GetCustomFieldDefiniations(fieldsAsGeneralIdRefs, cancellationToken); + + return new GetFormTemplate + { + Definition = currentVersion.FormDefinition, + Guid = formTemplate.Guid, + Id = formTemplate.Id, + Name = formTemplate.Name, + Version = currentVersion.Version, + CustomFieldDefinitions = customFieldDefinitions + }; + } + + private async Task GetCurrentVersionFromTemplate(FormTemplate formTemplate, CancellationToken cancellationToken) + { + if (_currentFormTemplateVersionCache.TryGetValue(formTemplate, out var template)) + return template; + + var currentFormTemplateVersion = await _formRepository.GetAllFormVersions(formTemplate.Id) + .OrderByDescending(fx => fx.Version).FirstAsync(fx => !fx.Deleted, cancellationToken); + + _currentFormTemplateVersionCache.Add(formTemplate, currentFormTemplateVersion); + + return currentFormTemplateVersion; + } + + private static readonly Dictionary> _customFieldsFromDefinitionCache = []; + + public static Task> GetCustomFieldsFromDefinition( string formDefinition ) + { + if (_customFieldsFromDefinitionCache.TryGetValue(formDefinition, out var definition)) + return Task.FromResult(definition); + + var doc = new HtmlDocument(); + doc.LoadHtml(formDefinition); + + //first I need to figure out the custom fields that are in the definition + var fieldsAsGeneralIdRefs = new List(); + + var nodes = doc.DocumentNode.SelectNodes("//span"); + + if (nodes != null) + { + foreach (var node in nodes) + { + if (node.Attributes.Contains("fieldType")) + { + if (node.Attributes["fieldType"].Value == "CustomField") + { + fieldsAsGeneralIdRefs.Add(new GeneralIdRef + { + Guid = Guid.Parse(node.Attributes["guid"].Value) + }); + } + } + } + } + + if (fieldsAsGeneralIdRefs.Count > 0) + _customFieldsFromDefinitionCache.Add(formDefinition, fieldsAsGeneralIdRefs); + + return Task.FromResult(fieldsAsGeneralIdRefs); + } + + private async Task> GetCustomFieldDefiniations(IEnumerable fieldsAsGeneralIdRefs, CancellationToken cancellationToken) + { + var results = new List(); + + var customFields = await GetCustomFields(fieldsAsGeneralIdRefs, cancellationToken); + + foreach (var customField in customFields) + results.Add(await _customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField, cancellationToken)); + + return results; + } + + private async Task> GetCustomFields(IEnumerable fieldsAsGeneralIdRefs, CancellationToken cancellationToken) + { + var results = new List(); + + foreach (var fieldRef in fieldsAsGeneralIdRefs) + { + var result = await _customFieldRepository.GetCustomFieldList().FindByGeneralIdRefAsync(fieldRef, cancellationToken) ?? throw new NotFoundException("Cannot find custom field"); + results.Add(result); + } + + return results; + } + + public async Task GetFormInstanceAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var formInstance = await _formRepository.GetFormInstance(generalIdRef,false, cancellationToken) ?? throw new NotFoundException("Unable to find form instance"); + var currentVersion = await GetCurrentVersionFromTemplate(formInstance.FormTemplateVersion.Template, cancellationToken); + var customFieldDefinitions = await GetCustomFieldDefinitions(formInstance.FormTemplateVersion, cancellationToken); + + var result = new ReadFormInstance + { + Id = formInstance.Id, + Guid = formInstance.Guid, + TemplateId = formInstance.FormTemplateVersion.Template.ToGeneralIdRef()!, + Name = formInstance.FormTemplateVersion.Template.Name, + Definition = formInstance.FormTemplateVersion.FormDefinition, + CustomFieldDefinitions = customFieldDefinitions, + CustomFieldValues = await _customFieldHelper.CustomFieldValuesList(formInstance.FormFields, cancellationToken), + Version = formInstance.FormTemplateVersion.Version, + UpdatedVersion = currentVersion.Version + }; + + return result; + } + + private readonly Dictionary> _getCustomFieldDefinitionsCache = []; + + private async Task> GetCustomFieldDefinitions(FormTemplateVersion formTemplateVersion, CancellationToken cancellationToken) + { + if (_getCustomFieldDefinitionsCache.TryGetValue(formTemplateVersion, out var definitions)) + return definitions; + + var fieldsAsGeneralIdRefs = await GetCustomFieldsFromDefinition(formTemplateVersion.FormDefinition); + List customFieldDefinitions = await GetCustomFieldDefiniations(fieldsAsGeneralIdRefs, cancellationToken); + _getCustomFieldDefinitionsCache.Add(formTemplateVersion, customFieldDefinitions); + + return customFieldDefinitions; + } + + public async Task> GetFormInstanceAsync(IEnumerable generalIdRefs, CancellationToken cancellationToken) + { + var results = new List(); + var formInstances = await _formRepository.GetFormInstances(generalIdRefs, false, cancellationToken); + foreach (var formInstance in formInstances) + { + var currentVersion = await GetCurrentVersionFromTemplate(formInstance.FormTemplateVersion.Template, cancellationToken); + var fieldsAsGeneralIdRefs = await GetCustomFieldsFromDefinition(formInstance.FormTemplateVersion.FormDefinition); + var customFieldDefinitions = await GetCustomFieldDefiniations(fieldsAsGeneralIdRefs, cancellationToken); + + var result = new ReadFormInstance + { + Id = formInstance.Id, + Guid = formInstance.Guid, + TemplateId = formInstance.FormTemplateVersion.Template.ToGeneralIdRef()!, + Name = formInstance.FormTemplateVersion.Template.Name, + Definition = formInstance.FormTemplateVersion.FormDefinition, + CustomFieldDefinitions = customFieldDefinitions, + CustomFieldValues = await _customFieldHelper.CustomFieldValuesList(formInstance.FormFields, cancellationToken), + Version = formInstance.FormTemplateVersion.Version, + UpdatedVersion = currentVersion.Version + }; + + results.Add(result); + } + + return results; + } + + public async Task CreateFormInstanceAsync( + AuditUserDetails auditUserDetails, + CreateFormInstance createFormInstance, + CancellationToken cancellationToken + ) + { + var template = await _formRepository.GetTemplateAsync(createFormInstance.TemplateId, cancellationToken ) ?? throw new NotFoundException("Unable to find template"); + var version = GetSpecificVersionFromTemplate(template, createFormInstance.Version) ?? throw new NotFoundException("Unable to find template version"); + var newFormInstance = new FormInstance + { + FormTemplateVersionId = version.Id, + Guid = createFormInstance.Guid ?? Guid.NewGuid() + }; + + await _formRepository.TransactionAsync(async () => + { + await _formRepository.AddFormInstance(auditUserDetails, newFormInstance, cancellationToken); + + var validatedFields = await CalculateValidatedCustomFieldValues(auditUserDetails, createFormInstance.CustomFieldValues, version, cancellationToken); + var customFieldValues = validatedFields.Select(validatedField => new FormFieldInstance + { + FormInstanceId = newFormInstance.Id, + CustomFieldId = validatedField.CustomFieldId, + Index = validatedField.Index, + Value = validatedField.Value, + DisplayValue = validatedField.DisplayValue! + }) + .ToList(); + + + await _formRepository.AddFormInstanceValues(auditUserDetails, customFieldValues, cancellationToken); + + }); + + + return new GeneralIdRef + { + Id = newFormInstance.Id, + Guid = newFormInstance.Guid, + }; + } + + + public struct FormInstanceDict + { + public FormInstance FormInstance { get; set; } + public CreateFormInstance CreateFormInstance { get; set; } + } + + public async Task CreateFormInstancesAsync(AuditUserDetails auditUserDetails, + IEnumerable createFormInstances, + CancellationToken cancellationToken) + { + var formInstances = new List(); + var templateVersionLookup = new Dictionary(); + + foreach (var createFormInstance in createFormInstances) + { + if (!templateVersionLookup.TryGetValue(createFormInstance.TemplateId, out var version)) + { + var template = + await _formRepository.GetTemplateAsync(createFormInstance.TemplateId, cancellationToken) ?? + throw new NotFoundException("Unable to find template"); + + version = GetSpecificVersionFromTemplate(template, createFormInstance.Version) ?? + throw new NotFoundException("Unable to find template version"); + templateVersionLookup.Add(createFormInstance.TemplateId, version); + } + + var newFormInstance = new FormInstanceDict + { + FormInstance = new FormInstance + { + FormTemplateVersion = version, + FormTemplateVersionId = version.Id, + Guid = createFormInstance.Guid ?? Guid.NewGuid() + }, + CreateFormInstance = createFormInstance + }; + + formInstances.Add(newFormInstance); + } + + await _formRepository.TransactionAsync(async () => + { + await _formRepository.AddFormInstances(auditUserDetails, formInstances.Select(x => x.FormInstance), + cancellationToken); + + var customFieldValues = new List(); + foreach (var formInstance in formInstances) + { + var validatedFields = await CalculateValidatedCustomFieldValues(auditUserDetails, + formInstance.CreateFormInstance.CustomFieldValues, + formInstance.FormInstance.FormTemplateVersion, cancellationToken); + + customFieldValues.AddRange( + validatedFields.Select(validatedField => new FormFieldInstance + { + FormInstanceId = formInstance.FormInstance.Id, + CustomFieldId = validatedField.CustomFieldId, + Index = validatedField.Index, + Value = validatedField.Value, + DisplayValue = validatedField.DisplayValue! + }) + ); + } + + await _formRepository.AddFormInstanceValues(auditUserDetails, customFieldValues, cancellationToken); + }); + } + + private FormTemplateVersion? GetSpecificVersionFromTemplate(FormTemplate template, long version) + { + return _formRepository.GetAllFormVersions(template.Id).SingleOrDefault(x => x.Version == version); + } + + private readonly Dictionary> _formVersionCustomFields = []; + + private async Task> CalculateValidatedCustomFieldValues( + AuditUserDetails auditUserDetails, + List customFieldValues, + FormTemplateVersion version, + CancellationToken cancellationToken + ) + { + if (!_formVersionCustomFields.TryGetValue(version, out var customFields)) + { + var fieldsAsGeneralIdRefs = await GetCustomFieldsFromDefinition(version.FormDefinition); + customFields = await GetCustomFields(fieldsAsGeneralIdRefs, cancellationToken); + + _formVersionCustomFields.Add(version,customFields); + } + + var inputFieldValues = customFieldValues.ToCustomFieldsValues(); + var validatedFields = + await _customFieldValidator.ValidateFields(auditUserDetails, inputFieldValues, customFields, cancellationToken); + return validatedFields; + } + + public async Task EditFormInstanceAsync( + AuditUserDetails auditUserDetails, + EditFormInstance editFormInstance, + CancellationToken cancellationToken + ) + { + await _formRepository.TransactionAsync(async () => + { + var formInstance = + await _formRepository.GetFormInstance(editFormInstance.FormInstanceId, true, cancellationToken) ?? throw new NotFoundException("FormInstance not found"); + if (formInstance.FormTemplateVersion.Version != editFormInstance.Version) + { + var formTemplate = + await _formRepository.GetTemplateAsync(editFormInstance.TemplateId, cancellationToken) ?? throw new NotFoundException("Template not found"); + var newVersion = formTemplate.Versions.SingleOrDefault(x => x.Version == editFormInstance.Version) ?? throw new NotFoundException("Version not found"); + formInstance.FormTemplateVersion = newVersion; + formInstance.FormTemplateVersionId = newVersion.Id; + } + + var validatedFields = await CalculateValidatedCustomFieldValues(auditUserDetails, editFormInstance.CustomFieldValues, formInstance.FormTemplateVersion, cancellationToken); + var customFieldValues = validatedFields.Select(validatedField => new FormFieldInstance + { + FormInstance = formInstance, + FormInstanceId = formInstance.Id, + CustomField = validatedField.CustomField, + CustomFieldId = validatedField.CustomFieldId, + Index = validatedField.Index, + Value = validatedField.Value, + DisplayValue = validatedField.DisplayValue! + }) + .ToList(); + + var formFieldValueKeyComparer = new FormFieldValueKeyComparer(); + var delta = Delta.CalculateDelta(customFieldValues, formInstance.FormFields, formFieldValueKeyComparer, cancellationToken); + + Parallel.ForEach(delta.Matches, match => + { + match.Original.DisplayValue = match.Updated.DisplayValue; + match.Original.Value = match.Updated.Value; + }); + + await _formRepository.SaveCustomFieldValues(auditUserDetails, delta, cancellationToken); + }); + } + + public Task EditFormInstanceAsync(AuditUserDetails auditUserDetails, IEnumerable editFormInstances, + CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/GlobalSuppressions.cs b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/IocRegistration.cs b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/IocRegistration.cs new file mode 100644 index 0000000..8c2a495 --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.FormsManager.Repository; + +namespace e_suite.Modules.FormsManager; + +public class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/Repository/FormRepository.cs b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/Repository/FormRepository.cs new file mode 100644 index 0000000..63396c2 --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/Repository/FormRepository.cs @@ -0,0 +1,154 @@ +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; + +namespace e_suite.Modules.FormsManager.Repository; + +public class FormRepository : RepositoryBase, IFormRepository +{ + public FormRepository(IEsuiteDatabaseDbContext databaseDbContext) + : base(databaseDbContext) + { + } + + + public async Task CreateNewFormVersionAsync(AuditUserDetails auditUserDetails, FormTemplateVersion formTemplateVersion, CancellationToken cancellationToken) + { + await DatabaseDbContext.FormTemplateVersions.AddAsync(formTemplateVersion, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task CreateTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate template, CancellationToken cancellationToken) + { + await DatabaseDbContext.FormTemplates.AddAsync(template, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteAllVersionsAsync(AuditUserDetails auditUserDetails, IEnumerable formVersions, CancellationToken cancellationToken) + { + DatabaseDbContext.FormTemplateVersions.UpdateRange(formVersions); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditFormTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate formTemplate, CancellationToken cancellationToken) + { + DatabaseDbContext.FormTemplates.Update(formTemplate); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetTemplateAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + return await DatabaseDbContext. + FormTemplates + //.Include(x => x.Versions) + .FindByGeneralIdRefAsync(id, cancellationToken); + } + + public IQueryable GetTemplates() + { + return DatabaseDbContext. + FormTemplates + //.Include( x=> x.Versions) + .Where(x => !x.Deleted); + } + + + public IQueryable GetAllFormVersions( + long templateId + ) + { + return DatabaseDbContext.FormTemplateVersions.Where(f => f.TemplateId == templateId); + } + + public Task GetTemplateWithOutLoadedRefereranceAsync(IGeneralIdRef id, + CancellationToken cancellationToken) + => DatabaseDbContext.FormTemplates.FindByGeneralIdRefAsync(id, cancellationToken); + + public Task GetFormTemplateVersionAsync(IGeneralIdRef templateId, CancellationToken cancellationToken) + => DatabaseDbContext.FormTemplateVersions.FindByGeneralIdRefAsync(templateId, cancellationToken); + + public Task GetFormTemplateWithSpecificVersionAsync(IGeneralIdRef id, long formTemplateVersionId, CancellationToken cancellationToken) + => DatabaseDbContext.FormTemplates.FindByGeneralIdRefAsync(id, cancellationToken); + + public async Task AddFormInstance(AuditUserDetails auditUserDetails, FormInstance newFormInstance, CancellationToken cancellationToken) + { + await AddFormInstances(auditUserDetails, [newFormInstance], cancellationToken); + } + + public async Task AddFormInstances(AuditUserDetails auditUserDetails, IEnumerable newFormInstances, CancellationToken cancellationToken) + { + await DatabaseDbContext.FormInstances.AddRangeAsync(newFormInstances, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task AddFormInstanceValues( + AuditUserDetails auditUserDetails, + List customFieldValues, + CancellationToken cancellationToken + ) + { + await DatabaseDbContext.FormFieldInstances.AddRangeAsync(customFieldValues, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetFormInstance(GeneralIdRef createFormInstanceId, bool tracking, CancellationToken cancellationToken) + { + var formInstances = LookupFormInstances(tracking); + return await formInstances.FindByGeneralIdRefAsync(createFormInstanceId, cancellationToken); + } + + private IQueryable LookupFormInstances(bool tracking) + { + IQueryable formInstances = DatabaseDbContext.FormInstances; + + if (!tracking) + { + formInstances = formInstances.AsNoTracking(); + } + + var results = formInstances.Include(x => x.FormTemplateVersion) + .ThenInclude(x => x.Template) + //.ThenInclude(x => x.Versions) + .Include(x => x.FormFields) + .ThenInclude(x => x.CustomField); + return results; + } + + public Task> GetFormInstances(IEnumerable generalIdRefs, bool tracking, CancellationToken cancellationToken) + { + var formInstances = LookupFormInstances(tracking); + + return Task.FromResult(formInstances.FindByGeneralIdRef(generalIdRefs).ToList()); + + } + + public async Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + await delta.UpdateDbSetAsync(DatabaseDbContext.FormFieldInstances, cancellationToken); + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task> GetFormsContainingFieldValue(IGeneralIdRef customFieldGeneralIdRef, string value, CancellationToken cancellationToken) + { + var customField = await DatabaseDbContext.CustomFields.FindByGeneralIdRefAsync(customFieldGeneralIdRef, cancellationToken); + + if (customField == null) + throw new NullReferenceException("Unable to find Custom field"); + + var formInstances = DatabaseDbContext.FormFieldInstances + .Where(x => x.CustomFieldId == customField.Id & x.Value == value) + .Include(x => x.FormInstance) + .Select(x => x.FormInstance); + + return formInstances; + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.csproj b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.csproj new file mode 100644 index 0000000..e894619 --- /dev/null +++ b/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager/e-suite.Modules.FormsManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.FormsManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FakeCustomFieldHelper.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FakeCustomFieldHelper.cs new file mode 100644 index 0000000..7c955e9 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FakeCustomFieldHelper.cs @@ -0,0 +1,38 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Modules.FormsManagerUnitTests; + +public class FakeCustomFieldHelper : ICustomFieldHelper +{ + public Task TranslateToCustomFieldDefinitionAsync(CustomField customField, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetGlossaryByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> CustomFieldValuesList(IEnumerable enumerableCustomFieldValues, CancellationToken cancellationToken) + { + return Task.FromResult(new List()); + } + + public Task GetDomainByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FakeFormsRepository.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FakeFormsRepository.cs new file mode 100644 index 0000000..b477d66 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FakeFormsRepository.cs @@ -0,0 +1,155 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.Forms; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.FormsManagerUnitTests; + +public class FakeFormsRepository : FakeRepository, IFormRepository +{ + public List FormTemplates { get; set; } = []; + public List FormTemplateVersions { get; set; } = []; + public List FormInstances { get; set; } = []; + + public List FormFieldValues { get; set; } = []; + + public Task CreateNewFormVersionAsync(AuditUserDetails auditUserDetails, FormTemplateVersion formTemplateVersion, CancellationToken cancellationToken) + { + FormTemplateVersions.Add(formTemplateVersion); + return Task.CompletedTask; + } + + public IQueryable GetAllFormVersions(long templateId) + { + return FormTemplateVersions.Where( x => x.TemplateId == templateId).ToList().BuildMock(); + } + + public Task CreateTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate template, CancellationToken cancellationToken) + { + FormTemplates.Add(template); + return Task.CompletedTask; + } + + public Task DeleteAllVersionsAsync(AuditUserDetails auditUserDetails, IEnumerable formTemplateVersions, CancellationToken cancellationToken) + { + FormTemplateVersions.ForEach(x => + { + if (formTemplateVersions.Any(f => f.Id == x.Id) || formTemplateVersions.Any(f => f.Guid == x.Guid)) + { + x.Deleted = true; + }; + }); + return Task.CompletedTask; + } + + public Task EditFormTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate formTemplate, CancellationToken cancellationToken) + { + var form = FormTemplates.First(x => x.Id == formTemplate.Id || x.Guid == formTemplate.Guid); + form.Name = formTemplate.Name; + return Task.CompletedTask; + } + +#pragma warning disable IDE0060 // Remove unused parameter + public Task> GetAllFormVersionsAsync(long templateId, CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + return Task.FromResult(FormTemplateVersions.Where(x => x.TemplateId == templateId)); + } + + public Task GetFormTemplateVersionAsync(IGeneralIdRef templateId, CancellationToken cancellationToken) + { + return Task.FromResult(FormTemplateVersions.FirstOrDefault(x => x.Id == templateId.Id || x.Guid == templateId.Guid)); + } + + public Task GetFormTemplateWithSpecificVersionAsync(IGeneralIdRef id, long formTemplateVersionId, CancellationToken cancellationToken) + { + return Task.FromResult(FormTemplates.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid)); + } + + public Task AddFormInstance( + AuditUserDetails auditUserDetails, + FormInstance newFormInstance, + CancellationToken cancellationToken + ) + { + FormInstances.Add(newFormInstance); + return Task.CompletedTask; + } + + public Task AddFormInstances(AuditUserDetails auditUserDetails, IEnumerable newFormInstance, + CancellationToken cancellationToken) + { + FormInstances.AddRange(newFormInstance); + return Task.CompletedTask; + } + + public Task AddFormInstanceValues( + AuditUserDetails auditUserDetails, + List customFieldValues, + CancellationToken cancellationToken + ) + { + FormFieldValues.AddRange(customFieldValues); + return Task.CompletedTask; + } + + public Task GetFormInstance(GeneralIdRef createFormInstanceId, bool tracking, CancellationToken cancellationToken) + { + return Task.FromResult(FormInstances.FindByGeneralIdRef(createFormInstanceId)); + } + + public Task> GetFormInstances(IEnumerable generalIdRefs, bool tracking, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + SaveCustomFieldValuesCalled = true; + return Task.CompletedTask; + } + + public Task> GetFormsContainingFieldValue(IGeneralIdRef customFieldGeneralIdRef, string value, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public bool SaveCustomFieldValuesCalled { get; set; } = false; + + public Task GetTemplateAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + var form = FormTemplates.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid); + if (form is null) + return Task.FromResult(form)!; + form!.Versions = [.. FormTemplateVersions.Where(f => f.TemplateId == form.Id).OrderBy(f => f.Version)]; + return Task.FromResult(form)!; + } + + public IQueryable GetTemplates() + { + return FormTemplates.BuildMock(); + } + +#pragma warning disable IDE0060 // Remove unused parameter + public Task> GetTemplatesAsync(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + return Task.FromResult((IEnumerable)FormTemplates); + } + + public Task GetTemplateWithOutLoadedRefereranceAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + var res = FormTemplates.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid); + if (res is null) + { + return Task.FromResult(res); + } + res.Versions = null!; + return Task.FromResult(res)!; + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormFieldValueKeyComparerUnitTests/CompareUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormFieldValueKeyComparerUnitTests/CompareUnitTests.cs new file mode 100644 index 0000000..371ee72 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormFieldValueKeyComparerUnitTests/CompareUnitTests.cs @@ -0,0 +1,209 @@ +using e_suite.Database.Core.Tables.Forms; +using e_suite.Modules.FormsManager; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormFieldValueKeyComparerUnitTests; + +[TestFixture] +public class CompareUnitTests +{ + private FormFieldValueKeyComparer _formFieldValueKeyComparer = null!; + + [SetUp] + public void SetUp() + { + _formFieldValueKeyComparer = new FormFieldValueKeyComparer(); + } + + [Test] + public void Compare_WhenBothNull_ReturnsEqual() + { + //Arrange + + //Act + var result = _formFieldValueKeyComparer.Compare(null, null); + + //Assert + Assert.That(result, Is.EqualTo(0)); + } + + [Test] + public void Compare_WhenXNull_ReturnsLower() + { + //Arrange + + //Act + var result = _formFieldValueKeyComparer.Compare(null, new FormFieldInstance()); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void Compare_WhenYNull_ReturnsHigher() + { + //Arrange + + //Act + var result = _formFieldValueKeyComparer.Compare(new FormFieldInstance(), null); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void Compare_WhenXFormInstanceIdLower_ReturnsLower() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 1 + }; + var y = new FormFieldInstance + { + FormInstanceId = 2 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x,y); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void Compare_WhenXFormInstanceIdHigher_ReturnsHigher() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 2 + }; + var y = new FormFieldInstance + { + FormInstanceId = 1 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void Compare_WhenXCustomFieldIdLower_ReturnsLower() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10 + }; + var y = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 20 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void Compare_WhenXCustomFieldIdHigher_ReturnsHigher() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 20 + }; + var y = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void Compare_WhenXIndexLower_ReturnsLower() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10, + Index = 100 + }; + var y = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10, + Index = 200 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void Compare_WhenXIndexHigher_ReturnsHigher() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10, + Index = 200 + }; + var y = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10, + Index = 100 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void Compare_WhenXAllEqual_ReturnsEqual() + { + //Arrange + var x = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10, + Index = 100 + }; + var y = new FormFieldInstance + { + FormInstanceId = 1, + CustomFieldId = 10, + Index = 100 + }; + + //Act + var result = _formFieldValueKeyComparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(0)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTestBase.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTestBase.cs new file mode 100644 index 0000000..f26851d --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTestBase.cs @@ -0,0 +1,73 @@ +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using Moq; + +namespace e_suite.Modules.FormsManagerUnitTests; + +public class FormsManagerUnitTestBase : TestBase +{ + protected FakeFormsRepository _fakeformRepository = null!; + protected FakeCustomFieldRepository customFieldRepository = null!; + protected Mock customFieldValidatorMock = null!; + protected FakeCustomFieldHelper customFieldHelper = null!; + protected AuditUserDetails auditResult = new(); + protected FormsManager.FormsManager _formManager = null!; + + public override async Task Setup() + { + await base.Setup(); + _fakeformRepository = new FakeFormsRepository(); + customFieldHelper = new FakeCustomFieldHelper(); + + customFieldValidatorMock = new Mock(); + + _formManager = new FormsManager.FormsManager(_fakeformRepository, customFieldRepository, customFieldHelper, customFieldValidatorMock.Object); + } +} + +public class FakeCustomFieldRepository : ICustomFieldRepository +{ + public Task TransactionAsync(Func> func) + { + throw new NotImplementedException(); + } + + public Task TransactionAsync(Func action) + { + throw new NotImplementedException(); + } + + public Task GetByIdAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetByNameAsync(string name, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditAsynch(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateAsync(AuditUserDetails auditUserDetails, CustomField customField, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public IQueryable GetCustomFieldList() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormInstanceAsyncUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormInstanceAsyncUnitTests.cs new file mode 100644 index 0000000..dff2147 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormInstanceAsyncUnitTests.cs @@ -0,0 +1,223 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +[TestFixture] +public class CreateFormInstanceAsyncUnitTests : FormsManagerUnitTestBase +{ + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public Task CreateFormInstanceAsync_WhenTemplateDoesNotExist_ThrowsError() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 726 + }; + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = new Guid("95dc0407-000a-4e11-891e-1a9c41e1a89a") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.CreateFormInstanceAsync(auditUserDetails, formInstance, CancellationToken.None); + }); + + Assert.That(actualResult.Message, Is.EqualTo("Unable to find template")); + return Task.CompletedTask; + } + + [Test] + public Task CreateFormInstanceAsync_WhenTemplateVersionDoesNotExist_ThrowsError() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 726 + }; + + var template = new FormTemplate + { + Guid = new Guid("8602d300-a364-4124-8e73-3ad3a237abe6"), + Id = 8472, + Name = "My Template" + }; + + _fakeformRepository.FormTemplates.Add(template); + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = template.Guid + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.CreateFormInstanceAsync(auditUserDetails, formInstance, CancellationToken.None); + }); + + Assert.That(actualResult.Message, Is.EqualTo("Unable to find template version")); + return Task.CompletedTask; + } + + [Test] + public async Task CreateFormInstanceAsync_WhenEverythingExists_CreatesFormInstance() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 5618 + }; + + var template = new FormTemplate + { + Guid = new Guid("8602d300-a364-4124-8e73-3ad3a237abe6"), + Id = 8472, + Name = "My Template" + }; + + var templateVersion = new FormTemplateVersion + { + Guid = new Guid("6d5e06d7-e8e4-4757-9795-41324b2501a8"), + Id = 180, + FormDefinition = "

The rules of acquisition...

", + Version = 1, + Template = template, + TemplateId = template.Id + }; + + template.Versions.Add(templateVersion); + + _fakeformRepository.FormTemplates.Add(template); + _fakeformRepository.FormTemplateVersions.Add(templateVersion); + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = template.Guid + }, + Version = 1 + }; + + //Act + await _formManager.CreateFormInstanceAsync(auditUserDetails, formInstance, CancellationToken.None); + + //Assert + Assert.That( _fakeformRepository.FormInstances, Has.Count.EqualTo(1)); + } + + [Test] + public async Task CreateFormInstanceAsync_WhenFormInstanceHasValues_ValuesAreSaved() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 5618 + }; + + var template = new FormTemplate + { + Guid = new Guid("8602d300-a364-4124-8e73-3ad3a237abe6"), + Id = 8472, + Name = "My Template" + }; + + var templateVersion = new FormTemplateVersion + { + Guid = new Guid("6d5e06d7-e8e4-4757-9795-41324b2501a8"), + Id = 180, + FormDefinition = "

The rules of acquisition...

", + Version = 1, + Template = template, + TemplateId = template.Id + }; + + template.Versions.Add(templateVersion); + + _fakeformRepository.FormTemplates.Add(template); + _fakeformRepository.FormTemplateVersions.Add(templateVersion); + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = template.Guid + }, + Version = 1, + CustomFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("bf537a45-2d16-4cc4-9225-3c26e74d78a3") + }, + Values = new List + { + new(){DisplayValue = "Hello", Value = "Hello"} + } + } + } + }; + + var customFieldValues = new List(); + customFieldValues.Add(new() + { + CustomFieldId = 1, + CustomField = new CustomField + { + Guid = new Guid("8d901bf5-6fc5-43ce-aa73-8034fdb6b38d"), + Id = 1, + FieldType = FieldType.Text + }, + Index = 0, + Value = "Hello", + DisplayValue = "Hello" + }); + + var validatedFieldsResult = Task.FromResult(customFieldValues.AsEnumerable()); + + customFieldValidatorMock + .Setup(x => x.ValidateFields(It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(validatedFieldsResult); + + + //Act + await _formManager.CreateFormInstanceAsync(auditUserDetails, formInstance, CancellationToken.None); + + //Assert + Assert.That(_fakeformRepository.FormInstances, Has.Count.EqualTo(1)); + Assert.That(_fakeformRepository.FormFieldValues, Has.Count.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormInstancesAsyncUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormInstancesAsyncUnitTests.cs new file mode 100644 index 0000000..a53aca1 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormInstancesAsyncUnitTests.cs @@ -0,0 +1,223 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +[TestFixture] +public class CreateFormInstancesAsyncUnitTests : FormsManagerUnitTestBase +{ + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public Task CreateFormInstancesAsync_WhenTemplateDoesNotExist_ThrowsError() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 726 + }; + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = new Guid("95dc0407-000a-4e11-891e-1a9c41e1a89a") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.CreateFormInstancesAsync(auditUserDetails, [formInstance], CancellationToken.None); + }); + + Assert.That(actualResult.Message, Is.EqualTo("Unable to find template")); + return Task.CompletedTask; + } + + [Test] + public Task CreateFormInstancesAsync_WhenTemplateVersionDoesNotExist_ThrowsError() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 726 + }; + + var template = new FormTemplate + { + Guid = new Guid("8602d300-a364-4124-8e73-3ad3a237abe6"), + Id = 8472, + Name = "My Template" + }; + + _fakeformRepository.FormTemplates.Add(template); + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = template.Guid + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.CreateFormInstancesAsync(auditUserDetails, [formInstance], CancellationToken.None); + }); + + Assert.That(actualResult.Message, Is.EqualTo("Unable to find template version")); + return Task.CompletedTask; + } + + [Test] + public async Task CreateFormInstancesAsync_WhenEverythingExists_CreatesFormInstance() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 5618 + }; + + var template = new FormTemplate + { + Guid = new Guid("8602d300-a364-4124-8e73-3ad3a237abe6"), + Id = 8472, + Name = "My Template" + }; + + var templateVersion = new FormTemplateVersion + { + Guid = new Guid("6d5e06d7-e8e4-4757-9795-41324b2501a8"), + Id = 180, + FormDefinition = "

The rules of acquisition...

", + Version = 1, + Template = template, + TemplateId = template.Id + }; + + template.Versions.Add(templateVersion); + + _fakeformRepository.FormTemplates.Add(template); + _fakeformRepository.FormTemplateVersions.Add(templateVersion); + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = template.Guid + }, + Version = 1 + }; + + //Act + await _formManager.CreateFormInstancesAsync(auditUserDetails, [formInstance], CancellationToken.None); + + //Assert + Assert.That( _fakeformRepository.FormInstances, Has.Count.EqualTo(1)); + } + + [Test] + public async Task CreateFormInstancesAsync_WhenFormInstanceHasValues_ValuesAreSaved() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy the tester", + UserId = 5618 + }; + + var template = new FormTemplate + { + Guid = new Guid("8602d300-a364-4124-8e73-3ad3a237abe6"), + Id = 8472, + Name = "My Template" + }; + + var templateVersion = new FormTemplateVersion + { + Guid = new Guid("6d5e06d7-e8e4-4757-9795-41324b2501a8"), + Id = 180, + FormDefinition = "

The rules of acquisition...

", + Version = 1, + Template = template, + TemplateId = template.Id + }; + + template.Versions.Add(templateVersion); + + _fakeformRepository.FormTemplates.Add(template); + _fakeformRepository.FormTemplateVersions.Add(templateVersion); + + var formInstance = new CreateFormInstance + { + TemplateId = new GeneralIdRef + { + Guid = template.Guid + }, + Version = 1, + CustomFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("bf537a45-2d16-4cc4-9225-3c26e74d78a3") + }, + Values = new List + { + new(){DisplayValue = "Hello", Value = "Hello"} + } + } + } + }; + + var customFieldValues = new List(); + customFieldValues.Add(new() + { + CustomFieldId = 1, + CustomField = new CustomField + { + Guid = new Guid("8d901bf5-6fc5-43ce-aa73-8034fdb6b38d"), + Id = 1, + FieldType = FieldType.Text + }, + Index = 0, + Value = "Hello", + DisplayValue = "Hello" + }); + + var validatedFieldsResult = Task.FromResult(customFieldValues.AsEnumerable()); + + customFieldValidatorMock + .Setup(x => x.ValidateFields(It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(validatedFieldsResult); + + + //Act + await _formManager.CreateFormInstancesAsync(auditUserDetails, [formInstance], CancellationToken.None); + + //Assert + Assert.That(_fakeformRepository.FormInstances, Has.Count.EqualTo(1)); + Assert.That(_fakeformRepository.FormFieldValues, Has.Count.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormUnitTest.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormUnitTest.cs new file mode 100644 index 0000000..afba68c --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/CreateFormUnitTest.cs @@ -0,0 +1,97 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.Forms; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +public class CreateFormUnitTest : FormsManagerUnitTestBase +{ + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public void CreateForm_NormalConditionsAuteGenGuid_SaveChnges() + { + //Arrange + var formDef = "SomeJsonDeffff"; + var formName = "NameFormTest"; + var createFormTemplate = new CreateFormTemplate + { + Definition = formDef, + Guid = null, + Name = formName + }; + + //Act + _formManager.CreateFormTemplateAsync(auditResult, createFormTemplate, default).GetAwaiter().GetResult(); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeformRepository.FormTemplates, Has.Count.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplates[0].Name, Is.EqualTo(formName)); + Assert.That(_fakeformRepository.FormTemplateVersions, Has.Count.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplateVersions[0].Version, Is.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplateVersions[0].FormDefinition, Is.EqualTo(formDef)); + }); + } + + [Test] + public void CreateForm_NormalConditionsPredefindGuid_SaveChnges() + { + //Arrange + var formGuid = Guid.NewGuid(); + var formDef = "SomeFormDef"; + var formName = "SomeFormName"; + var createFormTemplate = new CreateFormTemplate + { + Definition = formDef, + Guid = formGuid, + Name = formName + }; + + //Act + _formManager.CreateFormTemplateAsync(auditResult, createFormTemplate, default).GetAwaiter().GetResult(); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeformRepository.FormTemplates, Has.Count.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplates[0].Guid, Is.EqualTo(formGuid)); + Assert.That(_fakeformRepository.FormTemplates[0].Name, Is.EqualTo(formName)); + Assert.That(_fakeformRepository.FormTemplateVersions, Has.Count.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplateVersions[0].Version, Is.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplateVersions[0].FormDefinition, Is.EqualTo(formDef)); + }); + } + + [Test] + public void CreateForm_WithExistingGuid_ThrowsException() + { + //Arrange + var existingGuid = Guid.NewGuid(); + var formTemplate = new FormTemplate + { + Deleted = false, + Guid = existingGuid, + Name = "Some" + }; + + //Act + _fakeformRepository.FormTemplates.Add(formTemplate); + + //Assert + var createFormTempalate = new CreateFormTemplate + { + Guid = existingGuid, + Name = "TEstst", + Definition = "Defff" + }; + Assert.ThrowsAsync(() => _formManager.CreateFormTemplateAsync(auditResult, createFormTempalate, default)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/DeleteFormUnitTest.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/DeleteFormUnitTest.cs new file mode 100644 index 0000000..1b9ba54 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/DeleteFormUnitTest.cs @@ -0,0 +1,127 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +public class DeleteFormUnitTest : FormsManagerUnitTestBase +{ + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public async Task DeleteForm_NormalConditions_SaveChanges() + { + //Arrange + var form = new FormTemplate + { + Deleted = false, + Guid = Guid.NewGuid(), + Name = "test", + Id = 1 + }; + + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "Test", + Guid = Guid.NewGuid(), + Id = 1, + Version = 0, + TemplateId = 1, + }; + + _fakeformRepository.FormTemplates.Add(form); + _fakeformRepository.FormTemplateVersions.Add(formVersion); + + var genralId = new GeneralIdRef + { + Id = 1 + }; + + _fakeformRepository.FormTemplateVersions.Add(formVersion); + _fakeformRepository.FormTemplates.Add(form); + + //Act + await _formManager.DeleteFormTemplateAsync(auditResult, genralId, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(form.Deleted, Is.EqualTo(true)); + Assert.That(formVersion.Deleted, Is.EqualTo(true)); + }); + } + + [Test] + public async Task DeleteForm_FormWithManyVersion_SaveChanges() + { + var form = new FormTemplate + { + Deleted = false, + Guid = Guid.NewGuid(), + Name = "test", + Id = 1 + }; + + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "Test", + Guid = Guid.NewGuid(), + Id = 1, + Version = 0, + TemplateId = 1, + }; + + var formVersionTwo = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "Test", + Guid = Guid.NewGuid(), + Id = 2, + Version = 1, + TemplateId = 1, + }; + + var formVersionThre = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "Test", + Guid = Guid.NewGuid(), + Id = 3, + Version = 2, + TemplateId = 1, + }; + + var genralId = new GeneralIdRef + { + Id = 1 + }; + + _fakeformRepository.FormTemplateVersions.AddRange(new FormTemplateVersion[] { formVersion, formVersionTwo, formVersionThre }); + _fakeformRepository.FormTemplates.Add(form); + + //Act + await _formManager.DeleteFormTemplateAsync(auditResult, genralId, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeformRepository.FormTemplates[0].Deleted, Is.EqualTo(true)); + Assert.That(_fakeformRepository.FormTemplateVersions[0].Deleted, Is.EqualTo(true)); + Assert.That(formVersionTwo.Deleted, Is.EqualTo(true)); + Assert.That(formVersionThre.Deleted, Is.EqualTo(true)); + }); + } + + [Test] + public void DeleteForm_IdDosentExists_ThrowsException() + { + Assert.ThrowsAsync(() => _formManager.DeleteFormTemplateAsync(auditResult, new GeneralIdRef { Id = 6 }, default)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/EditFormInstanceAsyncUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/EditFormInstanceAsyncUnitTests.cs new file mode 100644 index 0000000..5b5c69e --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/EditFormInstanceAsyncUnitTests.cs @@ -0,0 +1,200 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +[TestFixture] +public class EditFormInstanceAsyncUnitTests : FormsManagerUnitTestBase +{ + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public Task EditFormInstanceAsync_FormInstanceNotFound_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails(); + var editFormInstance = new EditFormInstance + { + FormInstanceId = new GeneralIdRef + { + Guid = new Guid("c882cb17-22e6-4470-a402-fe9d0b18d292") + } + }; + + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.EditFormInstanceAsync(auditUserDetails, editFormInstance, CancellationToken.None); + }); + + Assert.That(result, Is.Not.Null); + Assert.That(result!.Message, Is.EqualTo("FormInstance not found")); + return Task.CompletedTask; + } + + [Test] + public Task EditFormInstanceAsync_TemplateNotFound_ThrowsException() + { + //Arrange + var formTemplateVersion = new FormTemplateVersion() + { + Guid = new Guid("8a9bd69b-6da0-4b56-a49a-0634f270051c"), + Id = 6244 + }; + + var formInstance = new FormInstance + { + Guid = new Guid("e706f520-b0b0-48f9-b937-74e7588a74b9"), + Id = 5644, + FormTemplateVersion = formTemplateVersion, + FormTemplateVersionId = formTemplateVersion.Id + }; + + _fakeformRepository.FormInstances.Add(formInstance); + + var auditUserDetails = new AuditUserDetails(); + var editFormInstance = new EditFormInstance + { + FormInstanceId = new GeneralIdRef + { + Guid = formInstance.Guid + }, + TemplateId = new GeneralIdRef + { + Guid = new Guid("a81a688b-be8d-4154-af0e-d2de8e431cb9") + }, + Version = 10 + }; + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.EditFormInstanceAsync(auditUserDetails, editFormInstance, CancellationToken.None); + }); + + Assert.That(result, Is.Not.Null); + Assert.That(result!.Message, Is.EqualTo("Template not found")); + return Task.CompletedTask; + } + + [Test] + public Task EditFormInstanceAsync_TemplateVersionNotFound_ThrowsException() + { + //Arrange + var formTemplate = new FormTemplate + { + Guid = new Guid("5ea17325-f16b-4e58-a6a4-a50185b7ffd9"), + Id = 6564 + }; + + var formTemplateVersion = new FormTemplateVersion() + { + Guid = new Guid("b25d2d69-e14c-4940-b6e9-acb1960796ab"), + Id = 94237, + Version = 20 + }; + + formTemplate.Versions.Add(formTemplateVersion); + + var formInstance = new FormInstance + { + Guid = new Guid("e706f520-b0b0-48f9-b937-74e7588a74b9"), + Id = 5644, + FormTemplateVersion = formTemplateVersion, + FormTemplateVersionId = formTemplateVersion.Id + }; + + _fakeformRepository.FormTemplates.Add(formTemplate); + _fakeformRepository.FormTemplateVersions.Add(formTemplateVersion); + _fakeformRepository.FormInstances.Add(formInstance); + + var auditUserDetails = new AuditUserDetails(); + var editFormInstance = new EditFormInstance + { + FormInstanceId = new GeneralIdRef + { + Guid = formInstance.Guid + }, + TemplateId = new GeneralIdRef + { + Guid = formTemplate.Guid + }, + Version = 10 + }; + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.EditFormInstanceAsync(auditUserDetails, editFormInstance, CancellationToken.None); + }); + + Assert.That(result, Is.Not.Null); + Assert.That(result!.Message, Is.EqualTo("Version not found")); + return Task.CompletedTask; + } + + [Test] + public async Task EditFormInstanceAsync_VersionFound_SavesChanages() + { + //Arrange + var formTemplate = new FormTemplate + { + Guid = new Guid("5ea17325-f16b-4e58-a6a4-a50185b7ffd9"), + Id = 6564 + }; + + var formTemplateVersion = new FormTemplateVersion() + { + Guid = new Guid("b25d2d69-e14c-4940-b6e9-acb1960796ab"), + Id = 94237, + Version = 20 + }; + + formTemplate.Versions.Add(formTemplateVersion); + + var formInstance = new FormInstance + { + Guid = new Guid("e706f520-b0b0-48f9-b937-74e7588a74b9"), + Id = 5644, + FormTemplateVersion = formTemplateVersion, + FormTemplateVersionId = formTemplateVersion.Id, + FormFields = [] + }; + + _fakeformRepository.FormTemplates.Add(formTemplate); + _fakeformRepository.FormTemplateVersions.Add(formTemplateVersion); + _fakeformRepository.FormInstances.Add(formInstance); + + var auditUserDetails = new AuditUserDetails(); + var editFormInstance = new EditFormInstance + { + FormInstanceId = new GeneralIdRef + { + Guid = formInstance.Guid + }, + TemplateId = new GeneralIdRef + { + Guid = formTemplate.Guid + }, + Version = 20 + }; + + //Act + await _formManager.EditFormInstanceAsync(auditUserDetails, editFormInstance, CancellationToken.None); + + //Assert + Assert.That(_fakeformRepository.SaveCustomFieldValuesCalled, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/EditFormUnitTest.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/EditFormUnitTest.cs new file mode 100644 index 0000000..d328ea7 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/EditFormUnitTest.cs @@ -0,0 +1,192 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +public class EditFormUnitTest : FormsManagerUnitTestBase +{ + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public async Task EditForm_NormalConditions_SaveChanges() + { + //Arrange + var form = new FormTemplate + { + Guid = Guid.NewGuid(), + Deleted = false, + Id = 1, + Name = "Test", + }; + + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "testttt", + Id = 1, + Guid = Guid.NewGuid(), + TemplateId = 1, + Template = form + }; + + form.Versions = [ formVersion ]; + _fakeformRepository.FormTemplateVersions.Add(formVersion); + _fakeformRepository.FormTemplates.Add(form); + + var editForm = new EditFormTemplate + { + Definition = "EditedDef", + Name = "Edited", + Id = new GeneralIdRef + { + Id = 1 + } + }; + + //Act + await _formManager.EditFormTemplateAsync(auditResult, editForm, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeformRepository.FormTemplateVersions, Has.Count.EqualTo(2)); + Assert.That(_fakeformRepository.FormTemplateVersions[1].Version, Is.EqualTo(1)); + Assert.That(_fakeformRepository.FormTemplates[0].Name, Is.EqualTo("Edited")); + }); + } + [Test] + public void EditForm_NotExistingForm_ThrowException() + { + //Arrange + var editForm = new EditFormTemplate + { + Definition = "EditedDef", + Name = "Edited", + Id = new GeneralIdRef + { + Id = 1 + } + }; + + //Act & Assert + Assert.ThrowsAsync(() => _formManager.EditFormTemplateAsync(auditResult, editForm, default)); + } + + [Test] + public async Task EditForm_With3Version_SaveChangesAsync() + { + //Arrange + var form = new FormTemplate + { + Guid = Guid.NewGuid(), + Deleted = false, + Id = 1, + Name = "Test", + }; + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "testttt", + Id = 1, + Guid = Guid.NewGuid(), + TemplateId = 1, + Template = form, + Version = 1 + }; + var formVersionTwo = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "testttt", + Id = 2, + Guid = Guid.NewGuid(), + TemplateId = 1, + Template = form, + Version = 2 + }; + var formVersionThree = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "testttt", + Id = 3, + Guid = Guid.NewGuid(), + TemplateId = 1, + Template = form, + Version = 3 + }; + var editForm = new EditFormTemplate + { + Definition = "EditedDef", + Name = "Edited", + Id = new GeneralIdRef + { + Id = 1 + } + }; + form.Versions = [formVersionThree]; + _fakeformRepository.FormTemplateVersions.AddRange([formVersion, formVersionTwo, formVersionThree ]); + _fakeformRepository.FormTemplates.Add(form); + + //Act + await _formManager.EditFormTemplateAsync(auditResult, editForm, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(_fakeformRepository.FormTemplateVersions, Has.Count.EqualTo(4)); + Assert.That(_fakeformRepository.FormTemplateVersions[3].Version, Is.EqualTo(4)); + Assert.That(_fakeformRepository.FormTemplates[0].Name, Is.EqualTo("Edited")); + }); + + } + + [Test] + public async Task EditForm_OnlyNameDosentCreateANewVersion() + { + //Arrange + var editFormName = "SOmeeese"; + var form = new FormTemplate + { + Guid = Guid.NewGuid(), + Deleted = false, + Id = 1, + Name = "Test", + }; + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = editFormName, + Id = 1, + Guid = Guid.NewGuid(), + TemplateId = 1, + Template = form + }; + form.Versions = [ formVersion ]; + _fakeformRepository.FormTemplateVersions.Add(formVersion); + _fakeformRepository.FormTemplates.Add(form); + var editForm = new EditFormTemplate + { + Name = editFormName, + Id = new GeneralIdRef + { + Id = 1 + } + }; + + //Act + await _formManager.EditFormTemplateAsync(auditResult, editForm, default); + + //Asserts + Assert.Multiple(() => + { + Assert.That(form.Name, Is.EqualTo(editFormName)); + Assert.That(_fakeformRepository.FormTemplates, Has.Count.EqualTo(1)); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetAllFormsUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetAllFormsUnitTests.cs new file mode 100644 index 0000000..5f309cf --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetAllFormsUnitTests.cs @@ -0,0 +1,96 @@ +using e_suite.Database.Core.Tables.Forms; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +public class GetAllFormsUnitTests : FormsManagerUnitTestBase +{ + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public async Task GetAllForms_NormalConditions_ReturnsCollection() + { + //Arrange + var formGuidOne = Guid.NewGuid(); + var formGuidTwo = Guid.NewGuid(); + var form = new FormTemplate + { + Guid = formGuidOne, + Deleted = false, + Id = 1, + Name = "TestOne", + }; + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "testtttOne", + Id = 1, + Guid = Guid.NewGuid(), + TemplateId = 1, + Template = form + }; + var formTwo = new FormTemplate + { + Guid = formGuidTwo, + Deleted = false, + Id = 2, + Name = "TestTwo", + }; + var formVersionTwo = new FormTemplateVersion + { + Deleted = false, + FormDefinition = "testtttTwo", + Id = 1, + Guid = Guid.NewGuid(), + TemplateId = 2, + Template = formTwo + }; + form.Versions = new List { formVersion }; + formTwo.Versions = new List { formVersionTwo }; + _fakeformRepository.FormTemplates.AddRange(new FormTemplate[] { form, formTwo }); + _fakeformRepository.FormTemplateVersions.AddRange(new FormTemplateVersion[] { formVersion, formVersionTwo }); + + var paging = new Paging + { + SortKey = "name" + }; + + //Act + var res = await _formManager.GetFormTemplatesAsync(paging, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(res.Count, Is.EqualTo(2)); + Assert.That(res.Data.Any(f => f.Guid == formGuidOne)); + Assert.That(res.Data.Any(f => f.Guid == formGuidTwo)); + }); + } + + [Test] + public async Task GetAllForms_NoData_RturnsEmptyList() + { + //Arrange + var paging = new Paging + { + SortKey = "name" + }; + + //Act + var res = await _formManager.GetFormTemplatesAsync(paging, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(res, Is.Not.Null); + Assert.That(res.Count, Is.EqualTo(0)); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetCustomFieldsFromDefinitionUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetCustomFieldsFromDefinitionUnitTests.cs new file mode 100644 index 0000000..93fdc47 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetCustomFieldsFromDefinitionUnitTests.cs @@ -0,0 +1,47 @@ +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +[TestFixture] +public class GetCustomFieldsFromDefinitionUnitTests : FormsManagerUnitTestBase +{ + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public async Task GetCustomFieldsFromDefinition_ExtractsFieldInfoFromDefinition() + { + //Arrange + var formDefinition = ""; + + //Act + var result = await FormsManager.FormsManager.GetCustomFieldsFromDefinition(formDefinition); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(2)); + Assert.That(result[0].Guid, Is.EqualTo(new Guid("7e826fe9-1fe2-4a7d-82bd-d510773e9761"))); + Assert.That(result[1].Guid, Is.EqualTo(new Guid("a681c714-500c-4036-8470-40f8f107bfa0"))); + }); + } + + [Test] + public async Task GetCustomFieldsFromDefinition_DoesNotReturnsValuesThatAreNotCustomFields() + { + //Arrange + var formDefinition = "
"; + + //Act + var result = await FormsManager.FormsManager.GetCustomFieldsFromDefinition(formDefinition); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result, Has.Count.EqualTo(0)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetFormInstanceAsyncUnitTests.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetFormInstanceAsyncUnitTests.cs new file mode 100644 index 0000000..8db09ee --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetFormInstanceAsyncUnitTests.cs @@ -0,0 +1,106 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +[TestFixture] +public class GetFormInstanceAsyncUnitTests : FormsManagerUnitTestBase +{ + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public Task GetFormInstanceAsync_WhenInstanceDoesNotExists_ReturnsError() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("1b2f6e6a-b194-4e47-9482-98cee266a8ba") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await _formManager.GetFormInstanceAsync(generalIdRef, CancellationToken.None); + }); + + Assert.That(actualResult.Message, Is.EqualTo("Unable to find form instance")); + return Task.CompletedTask; + } + + [Test] + public async Task GetFormInstanceAsync_WhenInstanceExists_Returns() + { + //Arrange + + var formTemplate = new FormTemplate + { + Guid = new Guid("731a6698-55eb-4d92-bc1f-85246253a2f3"), + Id = 42, + Name = "Meaning of life the universe and everything", + Deleted = false + }; + + var formTemplateVersion = new FormTemplateVersion + { + Guid = new Guid("ebc4e58e-dac0-454c-8e1b-51855934309d"), + Id = 57, + FormDefinition = "

The meaning of life the universe and everything is...

", + Template = formTemplate, + TemplateId = formTemplate.Id, + Version = 1 + }; + + var formTemplateNewVersion = new FormTemplateVersion + { + Guid = new Guid("7b848071-4508-4567-bcb8-8f3276fb2d68"), + Id = 58, + FormDefinition = "

The meaning of life the universe and everything is chocolate

", + Template = formTemplate, + TemplateId = formTemplate.Id, + Version = 2 + }; + + formTemplate.Versions.Add(formTemplateVersion); + formTemplate.Versions.Add(formTemplateNewVersion); + + var forminstance = new FormInstance + { + Guid = new Guid("cdc03065-b0d8-498b-87a3-de5617de65bb"), + Id = 10, + FormTemplateVersion = formTemplateVersion, + FormTemplateVersionId = formTemplateVersion.Id + }; + + _fakeformRepository.FormTemplates.Add(formTemplate); + _fakeformRepository.FormTemplateVersions.Add(formTemplateVersion); + _fakeformRepository.FormTemplateVersions.Add(formTemplateNewVersion); + _fakeformRepository.FormInstances.Add(forminstance); + + var generalIdRef = new GeneralIdRef + { + Guid = forminstance.Guid + }; + + //Act + var result = await _formManager.GetFormInstanceAsync(generalIdRef, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result!.Guid, Is.EqualTo(forminstance.Guid)); + Assert.That(result.Id, Is.EqualTo(forminstance.Id)); + Assert.That(result.Definition, Is.EqualTo(formTemplateVersion.FormDefinition)); + Assert.That(result.Version, Is.EqualTo(formTemplateVersion.Version)); + Assert.That(result.UpdatedVersion, Is.EqualTo(formTemplateNewVersion.Version)); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetFormUnitTest.cs b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetFormUnitTest.cs new file mode 100644 index 0000000..7c947c6 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/FormsManagerUnitTests/GetFormUnitTest.cs @@ -0,0 +1,108 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Forms; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.FormsManagerUnitTests.FormsManagerUnitTests; + +public class GetFormUnitTest : FormsManagerUnitTestBase +{ + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public async Task GetForm_NormalConditions_GetsObj() + { + //Arrange + var firstFormName = "TestOne"; + var firstFormDefinition = "testtttOne"; + var secondFormName = "SomeNAme"; + var secondFormDefinition = "SOMESOMEDEFF"; + + var formGuidOne = new Guid("4691197a-9508-4c41-962b-c87491e28256"); + var formGuidTwo = new Guid("b520642a-f2b7-4fac-a766-1b0b29346139"); + + var form = new FormTemplate + { + Guid = formGuidOne, + Deleted = false, + Id = 1, + Name = firstFormName, + }; + var formVersion = new FormTemplateVersion + { + Deleted = false, + FormDefinition = firstFormDefinition, + Id = 10, + Guid = new Guid("f3bcd5a0-2782-477f-b809-0a1baf2d19c7"), + TemplateId = 1, + Template = form + }; + form.Versions = new List { formVersion }; + _fakeformRepository.FormTemplateVersions.Add(formVersion); + _fakeformRepository.FormTemplates.Add(form); + + var formTwo = new FormTemplate + { + Guid = formGuidTwo, + Deleted = false, + Id = 2, + Name = secondFormName, + }; + var formVersionTwo = new FormTemplateVersion + { + Deleted = false, + FormDefinition = secondFormDefinition, + Id = 20, + Guid = new Guid("4e591752-a8f6-4df9-9c6c-6214899b567d"), + TemplateId = 2, + Template = formTwo + }; + formTwo.Versions = new List { formVersionTwo }; + _fakeformRepository.FormTemplateVersions.Add(formVersionTwo); + _fakeformRepository.FormTemplates.Add(formTwo); + + var generalId = new GeneralIdRef + { + Id = form.Id, + Guid = form.Guid + }; + + var genralIdTwo = new GeneralIdRef + { + Id = formTwo.Id, + Guid = formTwo.Guid + }; + + //Act + var res = await _formManager.GetFormTemplateAsync(generalId, default); + var resTwo = await _formManager.GetFormTemplateAsync(genralIdTwo, default); + + //Assert + Assert.Multiple(() => + { + + Assert.That(res, Is.Not.Null); + Assert.That(res.Name, Is.EqualTo(firstFormName)); + Assert.That(res.Definition, Is.EqualTo(firstFormDefinition)); + Assert.That(resTwo, Is.Not.Null); + Assert.That(resTwo.Name, Is.EqualTo(secondFormName)); + Assert.That(resTwo.Definition, Is.EqualTo(secondFormDefinition)); + }); + } + + [Test] + public void GetForm_NonExistentId_ThrowsFormNotFoundException() + { + Assert.ThrowsAsync(() => _formManager.GetFormTemplateAsync(new GeneralIdRef { Guid = null, Id = 0 }, default)); + } + + [Test] + public void GetForm_NUllId_throwsException() + { + Assert.ThrowsAsync(() => _formManager.GetFormTemplateAsync(null!, default)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/e_suite.Modules.FormsManagerUnitTests.csproj b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/e_suite.Modules.FormsManagerUnitTests.csproj new file mode 100644 index 0000000..d2d7505 --- /dev/null +++ b/e-suite.Modules.FormsManager/e_suite.Modules.Form.ManagerUnitTest/e_suite.Modules.FormsManagerUnitTests.csproj @@ -0,0 +1,31 @@ + + + + net10.0 + enable + enable + + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Modules.FormsManager/nuget.config b/e-suite.Modules.FormsManager/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.FormsManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/.gitattributes b/e-suite.Modules.GlossariesManager/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.GlossariesManager/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/.gitignore b/e-suite.Modules.GlossariesManager/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.GlossariesManager/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.GlossariesManager/.runsettings b/e-suite.Modules.GlossariesManager/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/AddGlossaryEntryUnitTests.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/AddGlossaryEntryUnitTests.cs new file mode 100644 index 0000000..b2a8e8a --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/AddGlossaryEntryUnitTests.cs @@ -0,0 +1,475 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Audit.AuditEngine; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using GlossariesManager.UnitTests.Helpers; +using Moq; +using NUnit.Framework; + +namespace GlossariesManager.UnitTests; + +[TestFixture] +public class AddGlossaryEntryUnitTests : GlossariesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public Task AddGlossary_WhenAddingNewItem_AddsItemCorrectly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Name = "test root item", + }; + + //Act + GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(GlossariesManagerRepository.Glossaries.Count, Is.EqualTo(1)); + Assert.That(GlossariesManagerRepository.Glossaries[0].Guid, Is.Not.Null); + }); + + return Task.CompletedTask; + } + + [Test] + public Task AddGlossary_WhenParentIsNull_AddsNewRootItem() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Name = "test root item", + Parent = null! + }; + + //Act + GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(GlossariesManagerRepository.Glossaries.Count, Is.EqualTo(1)); + Assert.That(GlossariesManagerRepository.Glossaries[0].Guid, Is.Not.Null); + }); + return Task.CompletedTask; + } + + [Test] + public Task AddGlossary_WhenParentIsMissing_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Name = "test root item", + Parent = new GeneralIdRef + { + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}") + } + }; + + //Act & Assert + Assert.Multiple(() => + { + Assert.ThrowsAsync(async () => + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default)); + Assert.That(GlossariesManagerRepository.Glossaries.Count, Is.EqualTo(0)); + }); + + return Task.CompletedTask; + } + + + [Test] + public Task AddGlossary_WhenParentIsPresent_AddsNewItem() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var parentGlossaryItem = new NewGlossaryItem + { + Name = "test root item", + Parent = null!, + Guid = new Guid("{C2F67C75-FE0C-4388-B474-C1B22BEEF443}") + }; + + GlossariesManager.AddGlossaryItem(auditUserDetails, parentGlossaryItem, default); + + var glossaryItem = new NewGlossaryItem + { + Name = "Test Child Item", + Parent = new GeneralIdRef + { + Guid = parentGlossaryItem.Guid.Value + } + }; + + //Act + GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(GlossariesManagerRepository.Glossaries.Count, Is.EqualTo(2)); + Assert.That(GlossariesManagerRepository.Glossaries[1].Guid, Is.Not.Null); + }); + return Task.CompletedTask; + } + + [Test] + public async Task AddGlossary_WhenItemAlreadyExists_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Name = "test root item", + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}") + }; + + //Act + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + //Assert + Assert.ThrowsAsync(async () => await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default)); + } + + [Test] + public async Task AddGlossary_WhenItemDefinesCustomFields_AddsNewItem() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Name = "test root item", + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}"), + ChildCustomFieldDefinition = + [ + new() + { + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + }, + + new() + { + Guid = new Guid("{67E85B6D-B25D-4AA7-8148-0B52BA694967}") + } + ] + }; + + //Act + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(GlossariesManagerRepository.Glossaries.Count, Is.EqualTo(1)); + Assert.That(GlossariesManagerRepository.GlossaryCustomFields.Count, Is.EqualTo(2)); + + Assert.That(GlossariesManagerRepository.GlossaryCustomFields[0].CustomFieldId, + Is.EqualTo(GlossariesManagerRepository.CustomFields[0].Id)); + Assert.That(GlossariesManagerRepository.GlossaryCustomFields[0].GlossaryId, + Is.EqualTo(GlossariesManagerRepository.Glossaries[0].Id)); + + Assert.That(GlossariesManagerRepository.GlossaryCustomFields[1].CustomFieldId, + Is.EqualTo(GlossariesManagerRepository.CustomFields[1].Id)); + Assert.That(GlossariesManagerRepository.GlossaryCustomFields[1].GlossaryId, + Is.EqualTo(GlossariesManagerRepository.Glossaries[0].Id)); + }); + } + + [Test] + public void AddGlossary_WhenNoParentWithCustomFieldValues_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Name = "test root item", + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}"), + CustomFieldValues = + [ + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{ECFF9FD6-F853-45C4-8505-EC28AD7EEC17}") + } + } + ] + }; + + //Act & Assert + Assert.ThrowsAsync(async () => await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default)); + } + + [Test] + public async Task AddGlossary_WhenItemHasCustomFieldValuesAndDefinitionNotFound_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var rootGlossaryItem = new NewGlossaryItem + { + Name = "test root item", + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}"), + ChildCustomFieldDefinition = + [ + new() + { + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + }, + + new() + { + Guid = new Guid("{67E85B6D-B25D-4AA7-8148-0B52BA694967}") + } + ] + }; + + await GlossariesManager.AddGlossaryItem(auditUserDetails, rootGlossaryItem, default); + + var childGlossaryItem = new NewGlossaryItem + { + Parent = new GeneralIdRef { Guid = rootGlossaryItem.Guid }, + Name = "Test Item 1", + CustomFieldValues = + [ + new() + { + Id = new GeneralIdRef { Guid = new Guid("{699B9144-FBA5-406E-BF40-ED5F51D3E018}") }, + Values = + [ + new() + { + Value = "Hello World", + DisplayValue = "Hello World" + } + ] + } + ] + }; + + CustomFieldValidatorMock + .Setup(x => x.ValidateFields(It.IsAny(), It.IsAny>(), + It.IsAny>(), + It.IsAny())).Throws(new NullReferenceException()); + + //Act & Assert + Assert.ThrowsAsync(async () => await GlossariesManager.AddGlossaryItem(auditUserDetails, childGlossaryItem, default)); + } + + [Test] + public async Task AddGlossary_WhenItemHasCustomFieldValues_SavesValueCorrectly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var customField = GlossariesManagerRepository.CustomFields[0]; + + var rootGlossaryItem = new NewGlossaryItem + { + Name = "test root item", + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}"), + ChildCustomFieldDefinition = [customField.ToGeneralIdRef()!] + }; + + await GlossariesManager.AddGlossaryItem(auditUserDetails, rootGlossaryItem, default); + + var glossary = GlossariesManagerRepository.Glossaries[0]; + glossary.CustomFieldDefinitions = + [ + new() + { + Id = 1, + Glossary = glossary, + GlossaryId = glossary.Id, + CustomField = customField, + CustomFieldId = customField.Id + } + ]; + + var customFieldValue = new CustomFieldValue + { + Value = "Hello World", + DisplayValue = "Hello World" + }; + + var childGlossaryItem = new NewGlossaryItem + { + Parent = new GeneralIdRef { Guid = rootGlossaryItem.Guid }, + Name = "Test Item 1", + Guid = new Guid("4c76ee61-31d4-4a1c-a6dc-c3187fe9eb79"), + CustomFieldValues = + [ + new() + { + Id = customField.ToGeneralIdRef()!, + Values = [customFieldValue] + } + ] + }; + + var validatedFields = new List + { + new() + { + CustomField = customField, + CustomFieldId = customField.Id, + DisplayValue = customFieldValue.DisplayValue, + Value = customFieldValue.Value.ToString()! + } + }; + + CustomFieldValidatorMock.Setup( x => x.ValidateFields(It.IsAny(), + It.IsAny>(), + It.IsAny>(), + It.IsAny() + ) + ) + .Returns(Task.FromResult(validatedFields.AsEnumerable())); + + + //Act + await GlossariesManager.AddGlossaryItem(auditUserDetails, childGlossaryItem, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(GlossariesManagerRepository.Glossaries.Count, Is.EqualTo(2)); + Assert.That(GlossariesManagerRepository.Glossaries[0].Name, Is.EqualTo(rootGlossaryItem.Name)); + Assert.That(GlossariesManagerRepository.Glossaries[0].Guid, Is.EqualTo(rootGlossaryItem.Guid)); + Assert.That(GlossariesManagerRepository.Glossaries[1].Name, Is.EqualTo(childGlossaryItem.Name)); + Assert.That(GlossariesManagerRepository.Glossaries[1].Guid, Is.EqualTo(childGlossaryItem.Guid)); + + Assert.That(GlossariesManagerRepository.GlossaryCustomFieldValues.Count, Is.EqualTo(1)); + Assert.That(GlossariesManagerRepository.GlossaryCustomFieldValues[0].DisplayValue, Is.EqualTo(customFieldValue.DisplayValue)); + Assert.That(GlossariesManagerRepository.GlossaryCustomFieldValues[0].Value, Is.EqualTo(customFieldValue.Value)); + }); + } + + [Test] + public async Task AddGlossary_WhenInsertsValueInToNonExistentCustomField_ThrowsExpectedError() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var rootGlossaryItem = new NewGlossaryItem + { + Name = "test root item", + Guid = new Guid("{E94BA53F-6802-4045-BE8F-CA1047CB34F9}"), + ChildCustomFieldDefinition = + [ + new() + { + Guid = new Guid("{67E85B6D-B25D-4AA7-8148-0B52BA694967}") + } + ] + }; + + await GlossariesManager.AddGlossaryItem(auditUserDetails, rootGlossaryItem, default); + + var customField = GlossariesManagerRepository.CustomFields[0]; + + var glossary = GlossariesManagerRepository.Glossaries[0]; + glossary.CustomFieldDefinitions = + [ + new() + { + Id = 1, + Glossary = glossary, + GlossaryId = glossary.Id, + CustomField = customField, + CustomFieldId = customField.Id + } + ]; + + var childGlossaryItem = new NewGlossaryItem + { + Parent = new GeneralIdRef { Guid = rootGlossaryItem.Guid }, + Name = "Test Item 1", + CustomFieldValues = + [ + new() + { + Id = new GeneralIdRef { Guid = rootGlossaryItem.ChildCustomFieldDefinition[0].Guid }, + Values = + [ + new() + { + Value = "Hello World", + DisplayValue = "Hello World" + } + ] + } + ] + }; + + CustomFieldValidatorMock + .Setup(x => x.ValidateFields(It.IsAny(), It.IsAny>(), + It.IsAny>(), + It.IsAny())).Throws(new NullReferenceException()); + + //Act and Assert + Assert.ThrowsAsync(async () => + await GlossariesManager.AddGlossaryItem(auditUserDetails, childGlossaryItem, default)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/DeleteGlossaryUnitTests.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/DeleteGlossaryUnitTests.cs new file mode 100644 index 0000000..6ed42a3 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/DeleteGlossaryUnitTests.cs @@ -0,0 +1,161 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using GlossariesManager.UnitTests.Helpers; +using NUnit.Framework; + +namespace GlossariesManager.UnitTests; + +[TestFixture] +public class DeleteGlossaryUnitTests : GlossariesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteGlossaryItem_ItemDoesNotExist_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("{8A909C67-BC70-4FE2-8B5A-B5799B8E9E98}") + }; + + // Act & Assert + Assert.ThrowsAsync( async() => await GlossariesManager.DeleteGlossaryItem(auditUserDetails, generalIdRef,default) ); + } + + [Test] + public void DeleteGlossaryItem_ItemDoesAlreadyDeleted_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("{8A909C67-BC70-4FE2-8B5A-B5799B8E9E98}") + }; + + + GlossariesManagerRepository.Glossaries.Add( new Glossary + { + Id = 1, + Guid = generalIdRef.Guid.Value, + Deleted = true + }); + + // Act & Assert + Assert.ThrowsAsync(async () => await GlossariesManager.DeleteGlossaryItem(auditUserDetails, generalIdRef, default)); + } + + [Test] + public async Task DeleteGlossaryItem_ItemFound_ItemIsMarkedDeleted() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("{8A909C67-BC70-4FE2-8B5A-B5799B8E9E98}") + }; + + + GlossariesManagerRepository.Glossaries.Add(new Glossary + { + Id = 1, + Guid = generalIdRef.Guid.Value, + Deleted = false + }); + + // Act + await GlossariesManager.DeleteGlossaryItem(auditUserDetails, generalIdRef, default); + + //Assert + Assert.That(GlossariesManagerRepository.Glossaries[0].Deleted, Is.True); + } + + + [Test] + public async Task DeleteGlossaryItem_ItemHasChildren_ChildrenAreAlsoDeleted() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("{8A909C67-BC70-4FE2-8B5A-B5799B8E9E98}") + }; + + + var parentItem = new Glossary + { + Id = 1, + Guid = generalIdRef.Guid.Value, + Deleted = false + }; + + GlossariesManagerRepository.Glossaries.Add(parentItem); + + var unrelatedItem = new Glossary + { + Id = 2, + Guid = new Guid("{FF497364-1AB6-4316-9CB7-B27D06B5A469}"), + Deleted = false + }; + + GlossariesManagerRepository.Glossaries.Add(unrelatedItem); + + var childItem = new Glossary + { + Id = 3, + Guid = new Guid("{902958C9-0D46-458D-98A1-ED9602706FEF}"), + Deleted = false, + ParentId = parentItem.Id, + Parent = parentItem + }; + + GlossariesManagerRepository.Glossaries.Add(childItem); + + var grandChild = new Glossary + { + Id = 4, + Guid = new Guid("{72CD4B61-1EDB-494E-91FE-3A40AEC3FEC3}"), + Deleted = false, + ParentId = childItem.Id, + Parent = childItem + }; + + GlossariesManagerRepository.Glossaries.Add(grandChild); + + // Act + await GlossariesManager.DeleteGlossaryItem(auditUserDetails, generalIdRef, default); + + //Assert + Assert.That(GlossariesManagerRepository.Glossaries[0].Deleted, Is.True); + Assert.That(GlossariesManagerRepository.Glossaries[1].Deleted, Is.False); + Assert.That(GlossariesManagerRepository.Glossaries[2].Deleted, Is.True); + Assert.That(GlossariesManagerRepository.Glossaries[3].Deleted, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/EditGlossaryUnitTests.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/EditGlossaryUnitTests.cs new file mode 100644 index 0000000..0b9c43a --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/EditGlossaryUnitTests.cs @@ -0,0 +1,189 @@ +using System.Collections.ObjectModel; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using GlossariesManager.UnitTests.Helpers; +using NUnit.Framework; + +namespace GlossariesManager.UnitTests; + +[TestFixture] +internal class EditGlossaryUnitTests : GlossariesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task UpdateGlossaryItem_EditGlossaryName_ChangesNameSuccessfully() + { + // Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Guid = Guid.NewGuid(), + Name = "test root item", + }; + + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + var editedGlossaryItem = new EditGlossaryItem + { + Id = new GeneralIdRef + { + Guid = glossaryItem.Guid.Value + }, + Name = "New root item", + }; + + // Act + await GlossariesManager.UpdateGlossaryItem(auditUserDetails, editedGlossaryItem, default); + + var result = await GlossariesManager.GetGlossaryItem(auditUserDetails, new GeneralIdRef { Guid = glossaryItem.Guid }, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result!.Guid, Is.EqualTo(editedGlossaryItem.Id.Guid)); + Assert.That(result.Name, Is.EqualTo(editedGlossaryItem.Name)); + } + + [Test] + public void UpdateGlossaryItem_GlossaryNotFound_ThrowsException() + { + // Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var editedGlossaryItem = new EditGlossaryItem + { + Id = new GeneralIdRef + { + Guid = Guid.NewGuid() + }, + Name = "LithoSpec", + ChildCustomFieldDefinition = + [ + new() + { + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + } + + ] + }; + + // Act + // Assert + Assert.ThrowsAsync(async () => await GlossariesManager.UpdateGlossaryItem(auditUserDetails, editedGlossaryItem, default)); + } + + [Test] + public async Task UpdateGlossaryItem_AddCustomFieldDefinition_CustomFieldIsAddedCorrectly() + { + // Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryGuid = Guid.NewGuid(); + + GlossariesManagerRepository.Glossaries.Add( + new Glossary + { + Guid = glossaryGuid, + Id = 3, + Name = "TestItem", + Deleted = false, + CustomFieldDefinitions = [], + CustomFieldValues = [], + ParentId = null + }); + + // Act + var editedGlossaryItem = new EditGlossaryItem + { + Id = new GeneralIdRef + { + Id = 3, + Guid = glossaryGuid + }, + Name = "TestItem", + ChildCustomFieldDefinition = + [ + new() + { + Id = 1, + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + } + ] + }; + + await GlossariesManager.UpdateGlossaryItem(auditUserDetails, editedGlossaryItem, default); + + //// Assert + var result = await GlossariesManager.GetGlossaryItem(auditUserDetails, new GeneralIdRef { Guid = glossaryGuid }, default); + + Assert.That(result, Is.Not.Null); + Assert.That(result!.ChildCustomFieldDefinition, Is.Not.Null); + } + + [Test] + public void UpdateGlossaryItem_AddNonExistentCustomFieldDefinition_ThrowsException() + { + // Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryGuid = Guid.NewGuid(); + + GlossariesManagerRepository.Glossaries.Add( + new Glossary + { + Guid = glossaryGuid, + Id = 3, + Name = "TestItem", + Deleted = false, + CustomFieldDefinitions = [], + CustomFieldValues = [], + ParentId = null + }); + + // Act + var editedGlossaryItem = new EditGlossaryItem + { + Id = new GeneralIdRef + { + Id = 3, + Guid = glossaryGuid + }, + Name = "TestItem", + ChildCustomFieldDefinition = + [ + new() + { + Guid = new Guid("{0017142F-DE3C-4ED8-B8E9-230E6760B824}") + } + ] + }; + + //Act and Assert + Assert.ThrowsAsync( + () => GlossariesManager.UpdateGlossaryItem(auditUserDetails, editedGlossaryItem, default) ); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GetGlossaryUnitTest.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GetGlossaryUnitTest.cs new file mode 100644 index 0000000..4372d42 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GetGlossaryUnitTest.cs @@ -0,0 +1,223 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using GlossariesManager.UnitTests.Helpers; +using NUnit.Framework; + +namespace GlossariesManager.UnitTests; + +[TestFixture] +public class GetGlossaryUnitTest : GlossariesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetGlossaryItem_GettingWithGuid_ReturnsGlossaryItem() + { + // Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Guid = new Guid("01293627-166f-4e10-9967-4a9215aefd2c"), + Name = "LithoSpec", + ChildCustomFieldDefinition = new List + { + new() + { + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + }, + new() + { + Guid = new Guid("{67E85B6D-B25D-4AA7-8148-0B52BA694967}") + } + } + }; + + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + // Act + var glossary = await GlossariesManager.GetGlossaryItem(auditUserDetails, new GeneralIdRef { Guid = glossaryItem.Guid }, default); + + // Assert + Assert.Multiple(() => + { + Assert.That(glossary, Is.Not.Null); + Assert.That(glossary?.Name, Is.EqualTo(glossaryItem.Name)); + }); + } + + [Test] + public async Task GetGlossaryItem_GuidNotFound_ThrowsNotFoundException() + { + // Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Guid = new Guid("54952d68-5702-4f93-9b1b-23b49df80bcc"), + Name = "LithoSpec", + ChildCustomFieldDefinition = new List + { + new() + { + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + }, + new() + { + Guid = new Guid("{67E85B6D-B25D-4AA7-8148-0B52BA694967}") + } + } + }; + + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + + // Assert + Assert.ThrowsAsync( + // Act + async () => await GlossariesManager.GetGlossaryItem(auditUserDetails, new GeneralIdRef + { + Guid = new Guid("2d2bacf4-0945-4f42-ba07-e436d2e559e5") + }, default)); + } + + [Test] + public async Task GetGlossaryItem_HasChildren_ChildrenReturnsCorrectly() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + var glossaryItem = new NewGlossaryItem + { + Guid = new Guid("051cf552-65a6-494a-b4dd-4b671f8b1de1"), + Name = "ParemtItem", + }; + await GlossariesManager.AddGlossaryItem(auditUserDetails, glossaryItem, default); + + var childGlossaryItem = new NewGlossaryItem + { + Guid = new Guid("d792480c-9f22-42d5-b8eb-c6da1c664ed7"), + Name = "Child Item", + Parent = new GeneralIdRef + { + Guid = glossaryItem.Guid, + } + }; + await GlossariesManager.AddGlossaryItem(auditUserDetails, childGlossaryItem, default); + + //Act + var glossary = await GlossariesManager.GetGlossaryItem(auditUserDetails, new GeneralIdRef { Guid = glossaryItem.Guid }, default); + + //Assert + Assert.Multiple(() => + { + Assert.That(glossary, Is.Not.Null); + Assert.That(glossary!.Guid, Is.EqualTo(glossaryItem.Guid)); + Assert.That(glossary!.Children, Is.Not.Null); + Assert.That(glossary!.Children!.Count, Is.EqualTo(1)); + Assert.That(glossary!.Children![0].Guid, Is.EqualTo(childGlossaryItem.Guid)); + }); + } + + [Test] + public async Task GetGlossaryItem_WhenItemIsSeveralLevelsDeep_AllParentsReturned() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserDisplayName = "Testy McTester", + UserId = 666 + }; + + GlossariesManagerRepository.Glossaries.Add(new Glossary + { + Id = 1, + Guid = new Guid("{FA6566F8-B4B0-48C5-9985-336C9284796E}"), + Name = "System" + }); + + GlossariesManagerRepository.Glossaries.Add( new Glossary + { + Id = 3, + Guid = new Guid("2d2bacf4-0945-4f42-ba07-e436d2e559e5"), + Name = "Categories", + ParentId = 1 + } ); + + GlossariesManagerRepository.Glossaries.Add(new Glossary + { + Id = 4, + Guid = new Guid("51fb0e6a-6855-495e-bc9f-8d11036f3b7d"), + Name = "Star Wars Vehicles", + ParentId = 3 + }); + + GlossariesManagerRepository.Glossaries.Add(new Glossary + { + Id = 5, + Guid = new Guid("ff9fcd3c-c644-4a13-a704-03f940275e77"), + Name = "Rebel Alliance", + ParentId = 4 + }); + + GlossariesManagerRepository.Glossaries.Add(new Glossary + { + Id = 6, + Guid = new Guid("45317c71-a13c-471d-8fe3-70c331cbebf2"), + Name = "Star Fighers", + ParentId = 5 + }); + + var xWingGuid = new Guid("02f2800a-b5d5-45a2-b573-186595c56e5c"); + GlossariesManagerRepository.Glossaries.Add(new Glossary + { + Id = 7, + Guid = xWingGuid, + Name = "X-Wing", + ParentId = 6 + }); + + //Act + var glossary = await GlossariesManager.GetGlossaryItem(auditUserDetails, new GeneralIdRef { Guid = xWingGuid }, default); + + //Assert + var parentChain = new List + { + 7, + 6, + 5, + 4, + 3, + 1 + }; + + Assert.That(glossary, Is.Not.Null); + + var glossaryToCheck = glossary; + foreach (var item in parentChain) + { + Assert.That(glossaryToCheck, Is.Not.Null); + Assert.That(glossaryToCheck!.Id, Is.EqualTo(item)); + glossaryToCheck = glossaryToCheck.Parent; + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GlossariesManager.UnitTests.csproj b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GlossariesManager.UnitTests.csproj new file mode 100644 index 0000000..d49e765 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GlossariesManager.UnitTests.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GlossaryCustomFieldValueKeyComparerUnitTests.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GlossaryCustomFieldValueKeyComparerUnitTests.cs new file mode 100644 index 0000000..f3bb339 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/GlossaryCustomFieldValueKeyComparerUnitTests.cs @@ -0,0 +1,245 @@ +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.Modules.GlossariesManager; +using NUnit.Framework; + +namespace GlossariesManager.UnitTests; + +[TestFixture] +public class GlossaryCustomFieldValueKeyComparerUnitTests +{ + private GlossaryCustomFieldValueKeyComparer _comparer = null!; + + [SetUp] + public void Setup() + { + _comparer = new GlossaryCustomFieldValueKeyComparer(); + } + + [Test] + public void Compare_BothInputsNull_ReturnsEqual() + { + //Arrange + //Act + var result = _comparer.Compare(null, null); + //Assert + Assert.That(result, Is.EqualTo(0)); + } + + [Test] + public void Compare_FirstInputNull_ReturnsLow() + { + //Arrange + //Act + var result = _comparer.Compare(null, new GlossaryCustomFieldValue()); + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void Compare_SecondInputNull_ReturnsHigh() + { + //Arrange + //Act + var result = _comparer.Compare(new GlossaryCustomFieldValue(), null); + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void CompareGlossaryId_WhenXLower_ReturnsLow() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 2 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void CompareGlossaryId_WhenYLower_ReturnsHigh() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 2 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void CompareGlossaryId_WhenBothEqual_ReturnsEqual() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 2 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 2 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(0)); + } + + [Test] + public void CompareCustomFieldId_WhenXLower_ReturnsLow() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 20 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void CompareCustomFieldId_WhenYLower_ReturnsHigh() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 20 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void CompareCustomFieldId_WhenBothSame_ReturnsEqual() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(0)); + } + + [Test] + public void CompareIndex_WhenXLower_ReturnsLow() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10, + Index = 100 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10, + Index = 200 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(-1)); + } + + [Test] + public void CompareIndex_WhenYLower_ReturnsHigh() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10, + Index = 200 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10, + Index = 100 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void CompareIndex_WhenBothSame_ReturnsEqual() + { + //Arrange + var x = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10, + Index = 100 + }; + var y = new GlossaryCustomFieldValue + { + GlossaryId = 1, + CustomFieldId = 10, + Index = 100 + }; + + //Act + var result = _comparer.Compare(x, y); + + //Assert + Assert.That(result, Is.EqualTo(0)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/Helpers/GlossariesManagerTestBase.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/Helpers/GlossariesManagerTestBase.cs new file mode 100644 index 0000000..ff308a9 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/Helpers/GlossariesManagerTestBase.cs @@ -0,0 +1,28 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using GlossariesManager.UnitTests.Repository; +using Moq; + +namespace GlossariesManager.UnitTests.Helpers; + +public class GlossariesManagerTestBase : TestBase +{ + protected IGlossariesManager GlossariesManager = null!; + protected FakeGlossariesManagerRepository GlossariesManagerRepository { get; set; } = null!; + + protected Mock CustomFieldValidatorMock = null!; + + protected Mock CustomFieldHelperMock = null!; + + public override async Task Setup() + { + await base.Setup(); + + GlossariesManagerRepository = new FakeGlossariesManagerRepository(); + + CustomFieldValidatorMock = new Mock(); + CustomFieldHelperMock = new Mock(); + + GlossariesManager = new e_suite.Modules.GlossariesManager.GlossariesManager(GlossariesManagerRepository, CustomFieldValidatorMock.Object, CustomFieldHelperMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/Repository/FakeGlossariesManagerRepository.cs b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/Repository/FakeGlossariesManagerRepository.cs new file mode 100644 index 0000000..063cd7a --- /dev/null +++ b/e-suite.Modules.GlossariesManager/GlossariesManager.UnitTests/Repository/FakeGlossariesManagerRepository.cs @@ -0,0 +1,179 @@ +using Autofac.Features.Metadata; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.UnitTestCore; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace GlossariesManager.UnitTests.Repository; + +public class FakeGlossariesManagerRepository : FakeRepository, IGlossariesManagerRepository +{ + public FakeGlossariesManagerRepository() + { + CustomFields = + [ + new() + { + Id = 1, + Name = "CustomField1", + FieldType = FieldType.Text, + Guid = new Guid("{AA4D6C9C-EFE5-495B-993E-97C977EDF9D7}") + }, + + new() + { + Id = 2, + Name = "CustomField2", + FieldType = FieldType.Text, + Guid = new Guid("{67E85B6D-B25D-4AA7-8148-0B52BA694967}") + } + ]; + } + + public List Glossaries { get; set; } = []; + public List GlossaryCustomFields { get; set; } = []; + public List CustomFields { get; set; } + public List GlossaryCustomFieldValues { get; set; } = []; + + public Task AddGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossary, CancellationToken cancellationToken) + { + var items = new List + { + glossary + }; + AddGlossaryItems(auditUserDetails, items, cancellationToken); + + return Task.CompletedTask; + } + + public Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable items, CancellationToken cancellationToken) + { + foreach( var glossary in items) + Glossaries.Add(glossary); + + return Task.CompletedTask; + } + + public async Task GetParentGlossary(IGeneralIdRef? glossaryItemParent, CancellationToken cancellationToken) + { + if (glossaryItemParent == null) + return null; + + return await FindGlossary(glossaryItemParent, cancellationToken); + } + + public IQueryable GetGlossaryCustomFields(long glossaryId) + { + return GlossaryCustomFields.BuildMock() + .Where(x => x.GlossaryId == glossaryId); + } + + public Task SaveChildCustomFieldDefinitions(AuditUserDetails auditUserDetails, IReadOnlyList removalList, + IReadOnlyList additionList, CancellationToken cancellationToken) + { + foreach (var item in removalList) + GlossaryCustomFields.Remove(item); + + foreach (var glossaryCustomField in additionList) + { + glossaryCustomField.Glossary ??= Glossaries.Single(x => x.Id == glossaryCustomField.GlossaryId); + + glossaryCustomField.CustomField ??= CustomFields.Single(x => x.Id == glossaryCustomField.CustomFieldId); + + GlossaryCustomFields.Add(glossaryCustomField); + } + + return Task.CompletedTask; + } + + public Task> GetGlossaryCustomValues(IId glossary, CancellationToken cancellationToken) + { + return Task.FromResult(GlossaryCustomFieldValues.Where(x => x.GlossaryId == glossary.Id).ToList()); + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + foreach (var addition in delta.Additions) + { + GlossaryCustomFieldValues.Add(addition); + } + + //foreach(var deletion in delta.Deletions) + //{ + // GlossaryCustomFieldValues.Remove(deletion); + //} + + return Task.CompletedTask; + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable> deltas, CancellationToken cancellationToken) + { + foreach (var delta in deltas) + { + SaveCustomFieldValues(auditUserDetails, delta, cancellationToken); + } + + return Task.CompletedTask; + } + + public Task FindGlossary(IGeneralIdRef glossaryItemParent, CancellationToken cancellationToken) + { + var glossary = Glossaries.SingleOrDefault(x => x.Guid == glossaryItemParent.Guid | x.Id == glossaryItemParent.Id); + if (glossary != null) + glossary.CustomFieldDefinitions = new Collection(GlossaryCustomFields.Where(x => x.GlossaryId == glossary.Id).ToList()); + + return Task.FromResult(glossary); + } + + + public Task> FindGlossaryChildren(long parentId, CancellationToken cancellationToken) + { + var children = Glossaries.Where(x => x.ParentId == parentId).ToList(); + + return Task.FromResult>(children); + } + + public Task> GetCustomFieldDefinitions(IEnumerable customFields, CancellationToken cancellationToken) + { + var result = new List(); + + foreach (var customField in customFields) + { + var field = CustomFields.FindByGeneralIdRef(customField); + + if (field != null) + result.Add(field); + else + throw new NullReferenceException(); + } + + return Task.FromResult(result); + } + +#pragma warning disable IDE0060 // Remove unused parameter + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable glossaryCustomFieldValues, CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + foreach (var glossaryCustomFieldValue in glossaryCustomFieldValues) + { + GlossaryCustomFieldValues.Add(glossaryCustomFieldValue); + } + + return Task.CompletedTask; + } + + public Task EditGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossaryItem, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/README.md b/e-suite.Modules.GlossariesManager/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.GlossariesManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/azure-pipelines.yml b/e-suite.Modules.GlossariesManager/azure-pipelines.yml new file mode 100644 index 0000000..6c848e0 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.sln b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.sln new file mode 100644 index 0000000..1f417ad --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32811.315 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.GlossariesManager", "e-suite.Modules.GlossariesManager\e-suite.Modules.GlossariesManager.csproj", "{7C619B16-DADE-4426-B307-77F1B1F56B6F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{D30E0E2E-B2C2-4EE5-A6B6-B35DA46DB3B8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{1E675F23-AE2F-49A9-80B4-1F5B1A74B032}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GlossariesManager.UnitTests", "GlossariesManager.UnitTests\GlossariesManager.UnitTests.csproj", "{0556B4C3-5019-4E55-9931-F799E0EF44CC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7C619B16-DADE-4426-B307-77F1B1F56B6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C619B16-DADE-4426-B307-77F1B1F56B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C619B16-DADE-4426-B307-77F1B1F56B6F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C619B16-DADE-4426-B307-77F1B1F56B6F}.Release|Any CPU.Build.0 = Release|Any CPU + {0556B4C3-5019-4E55-9931-F799E0EF44CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0556B4C3-5019-4E55-9931-F799E0EF44CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0556B4C3-5019-4E55-9931-F799E0EF44CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0556B4C3-5019-4E55-9931-F799E0EF44CC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1E675F23-AE2F-49A9-80B4-1F5B1A74B032} = {D30E0E2E-B2C2-4EE5-A6B6-B35DA46DB3B8} + {0556B4C3-5019-4E55-9931-F799E0EF44CC} = {1E675F23-AE2F-49A9-80B4-1F5B1A74B032} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FA91DCD9-AE21-4C91-B4C7-7B57B009A71D} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlobalSuppressions.cs b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossariesManager.cs b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossariesManager.cs new file mode 100644 index 0000000..7065217 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossariesManager.cs @@ -0,0 +1,318 @@ +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using e_suite.Database.Core.Tables.CustomFields; + +namespace e_suite.Modules.GlossariesManager; + +public class GlossariesManager : IGlossariesManager +{ + private readonly IGlossariesManagerRepository _glossariesManagerRepository; + private readonly ICustomFieldValidator _customFieldValidator; + private readonly ICustomFieldHelper _customFieldHelper; + + public GlossariesManager(IGlossariesManagerRepository glossariesManagerRepository, ICustomFieldValidator customFieldValidator, ICustomFieldHelper customFieldHelper) + { + _glossariesManagerRepository = glossariesManagerRepository; + _customFieldValidator = customFieldValidator; + _customFieldHelper = customFieldHelper; + } + + public async Task GetGlossaryItem(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var glossary = await _glossariesManagerRepository.FindGlossary(generalIdRef, cancellationToken) ?? + throw new NotFoundException("Glossary not found"); + + await LoadParentHierarchy(glossary, cancellationToken); + + var glossaryItem = await GlossaryItemHelper.TranslateToGlossaryItem(glossary, _customFieldHelper, cancellationToken); + if (glossaryItem == null) + return glossaryItem; + + var children = await _glossariesManagerRepository.FindGlossaryChildren(glossaryItem.Id, cancellationToken); + + var childGlossaryItems = new List(); + foreach (var child in children) + { + if (!child.Deleted) + { + childGlossaryItems.Add((await GlossaryItemHelper.TranslateToGlossaryItem(child, _customFieldHelper, cancellationToken))!); + } + } + + glossaryItem.Children = childGlossaryItems; + + return glossaryItem; + } + + private async Task LoadParentHierarchy(Glossary glossary, CancellationToken cancellationToken) + { + var item = glossary; + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + while (item != null) + { + item.Parent ??= (await _glossariesManagerRepository.FindGlossary(new GeneralIdRef { Id = item.ParentId }, cancellationToken))!; + + item = item.Parent; + } + } + + public async Task AddGlossaryItem(AuditUserDetails auditUserDetails, NewGlossaryItem glossaryItem, CancellationToken cancellationToken) + { + await _glossariesManagerRepository.TransactionAsync(async () => + { + await DoAddGlossaryItem(auditUserDetails, [glossaryItem], cancellationToken); + }); + } + + public async Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable glossaryItems, CancellationToken cancellationToken) + { + await _glossariesManagerRepository.TransactionAsync(async () => + { + await DoAddGlossaryItem(auditUserDetails, glossaryItems, cancellationToken); + }); + } + + private async Task DoAddGlossaryItem(AuditUserDetails auditUserDetails, IEnumerable glossaryItems, + CancellationToken cancellationToken) + { + var itemsToWorkOn = new List<(NewGlossaryItem, Glossary)>(); + + foreach (var glossaryItem in glossaryItems) + { + var parent = + await _glossariesManagerRepository.GetParentGlossary(glossaryItem.Parent, cancellationToken); + + if (glossaryItem.Parent != null && parent == null) + throw new NullReferenceException("parent could not be found"); + + var duplicate = glossaryItem.Guid == null + ? null + : await _glossariesManagerRepository.FindGlossary(new GeneralIdRef { Guid = glossaryItem.Guid }, + cancellationToken); + + if (duplicate != null) + throw new ArgumentException($"Guid {glossaryItem.Guid} is already used"); + + var glossary = new Glossary + { + Deleted = false, + Guid = glossaryItem.Guid ?? Guid.NewGuid(), + Name = glossaryItem.Name, + ParentId = parent?.Id, + Parent = parent! + }; + + itemsToWorkOn.Add(new ValueTuple + { + Item1 = glossaryItem, + Item2 = glossary + }); + } + + await _glossariesManagerRepository.AddGlossaryItems(auditUserDetails, itemsToWorkOn.Select(x => x.Item2), + cancellationToken); + await UpdateChildCustomFieldDefinitions(auditUserDetails, + itemsToWorkOn.Select(x => + new ValueTuple, Glossary> + { + Item1 = x.Item1.ChildCustomFieldDefinition, + Item2 = x.Item2 + } + ), + cancellationToken); + await UpdateCustomFieldValues(auditUserDetails, itemsToWorkOn.Select(x => + new ValueTuple + { + Item1 = x.Item1, + Item2 = x.Item2 + } + ), cancellationToken); + } + + + public async Task UpdateGlossaryItem(AuditUserDetails auditUserDetails, EditGlossaryItem editGlossaryItem, CancellationToken cancellationToken) + { + await _glossariesManagerRepository.TransactionAsync(async () => + { + var glossaryItem = await _glossariesManagerRepository.FindGlossary(editGlossaryItem.Id, cancellationToken) ?? + throw new ArgumentNullException(nameof(editGlossaryItem),"Glossary item not found"); + + glossaryItem.Name = editGlossaryItem.Name; + + await UpdateChildCustomFieldDefinitions(auditUserDetails, glossaryItem, editGlossaryItem.ChildCustomFieldDefinition, cancellationToken); + await UpdateCustomFieldValues(auditUserDetails, glossaryItem, editGlossaryItem, cancellationToken); + + await _glossariesManagerRepository.EditGlossaryItem(auditUserDetails, glossaryItem, cancellationToken); + }); + } + + private async Task UpdateCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable<(EditableGlossaryItem, Glossary)> itemsToWorkOn, + CancellationToken cancellationToken) + { + List> deltas = []; + + foreach (var item in itemsToWorkOn) + { + if (item.Item2.Parent == null && item.Item1.CustomFieldValues.Count > 0) + throw new NullReferenceException("Root items cannot have custom field values."); + + var updatedcustomFieldValues = + await CompileGlossaryCustomFieldValues(auditUserDetails, item.Item1, item.Item2.Parent, item.Item2, + cancellationToken); + + var currentCustomFieldValues = await _glossariesManagerRepository.GetGlossaryCustomValues(item.Item2, cancellationToken); + + var glossaryCustomFieldValueKeyComparer = new GlossaryCustomFieldValueKeyComparer(); + Delta delta = Delta.CalculateDelta(updatedcustomFieldValues, currentCustomFieldValues, glossaryCustomFieldValueKeyComparer, cancellationToken); + + Parallel.ForEach(delta.Matches, match => + { + match.Original.DisplayValue = match.Updated.DisplayValue; + match.Original.Value = match.Updated.Value; + }); + + deltas.Add(delta); + } + + await _glossariesManagerRepository.SaveCustomFieldValues(auditUserDetails, deltas, cancellationToken); + } + + private async Task UpdateCustomFieldValues(AuditUserDetails auditUserDetails, Glossary glossaryItem, + EditableGlossaryItem glossary, CancellationToken cancellationToken) + { + var items = new List<(EditableGlossaryItem, Glossary)> + { + new() + { + Item1 = glossary, + Item2 = glossaryItem + } + }; + + await UpdateCustomFieldValues(auditUserDetails, items, cancellationToken); + + } + + private async Task UpdateChildCustomFieldDefinitions(AuditUserDetails auditUserDetails, Glossary glossary, + IEnumerable customFieldIds, CancellationToken cancellationToken) + { + var itemsToWorkOn = new List<(IEnumerable, Glossary)> + { + new() + { + Item1 = customFieldIds, + Item2 = glossary + } + }; + + await UpdateChildCustomFieldDefinitions(auditUserDetails, + itemsToWorkOn, cancellationToken); + } + + private async Task UpdateChildCustomFieldDefinitions(AuditUserDetails auditUserDetails, + IEnumerable<(IEnumerable, Glossary)> itemsToWorkOn, CancellationToken cancellationToken) + { + var removalList = new List(); + var additionList = new List(); + + foreach (var item in itemsToWorkOn) + { + List customFieldDefinitions; + try + { + customFieldDefinitions = + await _glossariesManagerRepository.GetCustomFieldDefinitions(item.Item1, cancellationToken); + } + catch (NullReferenceException ex) + { + throw new NotFoundException("Unable to find custom field", ex); + } + + foreach (var customField in _glossariesManagerRepository.GetGlossaryCustomFields(item.Item2.Id)) + { + var found = false; + foreach (var a in customFieldDefinitions) + { + if (a.Id == customField.Id) + { + found = true; + break; + } + } + + if (!found) + removalList.Add(customField); + } + + foreach (var customFieldDefinition in customFieldDefinitions) + { + cancellationToken.ThrowIfCancellationRequested(); + var glossaryCustomField = new GlossaryCustomField + { + GlossaryId = item.Item2.Id, + CustomFieldId = customFieldDefinition.Id + }; + + additionList.Add(glossaryCustomField); + } + } + + await _glossariesManagerRepository.SaveChildCustomFieldDefinitions(auditUserDetails, removalList, additionList, cancellationToken); + } + + private async Task> CompileGlossaryCustomFieldValues(AuditUserDetails auditUserDetails, EditableGlossaryItem glossaryItem, Glossary? parent, Glossary glossary, CancellationToken cancellationToken) + { + if (parent == null) + return []; + + var parentCustomFieldDefinitions = parent.CustomFieldDefinitions.Select(x => x.CustomField).ToList(); + + var inputFieldValues = glossaryItem.CustomFieldValues.ToCustomFieldsValues(); + + var validatedFields = await _customFieldValidator.ValidateFields(auditUserDetails, inputFieldValues, parentCustomFieldDefinitions, cancellationToken); + + return validatedFields.Select(validatedField => new GlossaryCustomFieldValue + { + GlossaryId = glossary.Id, + CustomFieldId = validatedField.CustomFieldId, + Index = validatedField.Index, + Value = validatedField.Value, + DisplayValue = validatedField.DisplayValue! + }) + .ToList(); + } + + + public async Task DeleteGlossaryItem(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + await _glossariesManagerRepository.TransactionAsync(async () => + { + var glossaryItem = await _glossariesManagerRepository.FindGlossary(generalIdRef, cancellationToken) ?? + throw new NotFoundException("Unable to find glossary item"); + + if (glossaryItem!.Deleted) + throw new InvalidOperationException("Already deleted"); + + await SetItemAndChildrenAsDeleted(glossaryItem, cancellationToken); + + await _glossariesManagerRepository.EditGlossaryItem(auditUserDetails, glossaryItem, cancellationToken); + }); + } + + private async Task SetItemAndChildrenAsDeleted(Glossary glossaryItem, CancellationToken cancellationToken) + { + var children = await _glossariesManagerRepository.FindGlossaryChildren(glossaryItem.Id, cancellationToken); + foreach (var child in children) + { + await SetItemAndChildrenAsDeleted(child, cancellationToken); + } + + glossaryItem.Deleted = true; + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossaryCustomFieldValueKeyComparer.cs b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossaryCustomFieldValueKeyComparer.cs new file mode 100644 index 0000000..c232b46 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossaryCustomFieldValueKeyComparer.cs @@ -0,0 +1,19 @@ +using e_suite.Database.Core.Tables.Glossaries; + +namespace e_suite.Modules.GlossariesManager; + +public class GlossaryCustomFieldValueKeyComparer : IComparer +{ + public int Compare(GlossaryCustomFieldValue? x, GlossaryCustomFieldValue? y) + { + if (ReferenceEquals(x, y)) return 0; + if (y is null) return 1; + if (x is null) return -1; + + var glossaryIdComparison = x.GlossaryId.CompareTo(y.GlossaryId); + if (glossaryIdComparison != 0) return glossaryIdComparison; + var customFieldIdComparison = x.CustomFieldId.CompareTo(y.CustomFieldId); + if (customFieldIdComparison != 0) return customFieldIdComparison; + return x.Index.CompareTo(y.Index); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossaryItemHelper.cs b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossaryItemHelper.cs new file mode 100644 index 0000000..2b469e3 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/GlossaryItemHelper.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common.models; +using e_suite.API.Common; +using e_suite.Database.Core.Tables.Glossaries; + +namespace e_suite.Modules.GlossariesManager; + +public static class GlossaryItemHelper +{ + public static async Task TranslateToGlossaryItem(Glossary glossary, ICustomFieldHelper customFieldHelper, CancellationToken cancellationToken) + { + var result = new GlossaryItem + { + Id = glossary.Id, + Guid = glossary.Guid, + Name = glossary.Name, + + }; + + if (glossary.Parent != null) + { + result.Parent = await TranslateToGlossaryItem(glossary.Parent, customFieldHelper, cancellationToken); + } + + var customFieldDefinitions = new List(); + foreach (var customField in glossary.CustomFieldDefinitions) + { + customFieldDefinitions.Add(await customFieldHelper.TranslateToCustomFieldDefinitionAsync(customField.CustomField, cancellationToken)); + } + + result.ChildCustomFieldDefinition = customFieldDefinitions; + + if (result.ChildCustomFieldDefinition.Count == 0) + result.ChildCustomFieldDefinition = null; + + var customFieldValues = await customFieldHelper.CustomFieldValuesList(glossary.CustomFieldValues, cancellationToken); + result.CustomFieldValues = customFieldValues; + + if (result.CustomFieldValues?.Count == 0) + result.CustomFieldValues = null; + + return result; + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/IocRegistration.cs b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/IocRegistration.cs new file mode 100644 index 0000000..035270c --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.GlossariesManager.Repository; + +namespace e_suite.Modules.GlossariesManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/Repository/GlossariesManagerRepository.cs b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/Repository/GlossariesManagerRepository.cs new file mode 100644 index 0000000..871ffcd --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/Repository/GlossariesManagerRepository.cs @@ -0,0 +1,129 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Helpers; + +namespace e_suite.Modules.GlossariesManager.Repository; + +public class GlossariesManagerRepository : RepositoryBase, IGlossariesManagerRepository +{ + public GlossariesManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public async Task AddGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossary, CancellationToken cancellationToken) + { + var items = new List + { + glossary + }; + await AddGlossaryItems(auditUserDetails, items, cancellationToken); + } + + public async Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable items, CancellationToken cancellationToken) + { + foreach (var item in items) + await DatabaseDbContext.Glossaries.AddAsync(item, cancellationToken); + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetParentGlossary(IGeneralIdRef? glossaryItemParent, CancellationToken cancellationToken) + { + return glossaryItemParent == null + ? null + : await FindGlossary(glossaryItemParent, cancellationToken); + } + + public async Task FindGlossary(IGeneralIdRef glossaryItem, CancellationToken cancellationToken) => + await DatabaseDbContext.Glossaries + .Include(x => x.CustomFieldDefinitions) + .ThenInclude(x => x.CustomField) + .Include(x => x.CustomFieldValues) + .Include(x => x.Parent) + .ThenInclude( x=> x.CustomFieldDefinitions) + .ThenInclude( x=> x.CustomField) + .FindByGeneralIdRefAsync(glossaryItem, cancellationToken); + + public Task> FindGlossaryChildren(long parentId, CancellationToken cancellationToken) + { + return Task.FromResult>( DatabaseDbContext.Glossaries + .Include(x => x.CustomFieldDefinitions) + .ThenInclude(x => x.CustomField) + .Include(x => x.CustomFieldValues) + .Where(x => x.ParentId == parentId) ); + } + + public async Task> GetCustomFieldDefinitions(IEnumerable customFieldIdRefs, CancellationToken cancellationToken) + { + var list = new List(); + + foreach (var customFieldIdRef in customFieldIdRefs) + { + var customFieldDefinition = await DatabaseDbContext.CustomFields.FindByGeneralIdRefAsync(customFieldIdRef, cancellationToken); + if (customFieldDefinition != null) + list.Add(customFieldDefinition); + } + + return list; + } + + public IQueryable GetGlossaryCustomFields(long glossaryId) + { + return DatabaseDbContext.GlossaryCustomFields + .Where(x => x.GlossaryId == glossaryId); + } + + public async Task SaveChildCustomFieldDefinitions(AuditUserDetails auditUserDetails, IReadOnlyList removalList, IReadOnlyList additionList, + CancellationToken cancellationToken) + { + DatabaseDbContext.GlossaryCustomFields.RemoveRange(removalList); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + await DatabaseDbContext.GlossaryCustomFields.AddRangeAsync(additionList, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task> GetGlossaryCustomValues(IId glossary, CancellationToken cancellationToken) + { + return await DatabaseDbContext.GlossaryCustomFieldValues.Where(x => x.GlossaryId == glossary.Id).ToListAsync(cancellationToken); + } + + public async Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable> deltas, CancellationToken cancellationToken) + { + foreach (var delta in deltas) + { + await delta.UpdateDbSetAsync(DatabaseDbContext.GlossaryCustomFieldValues, cancellationToken); + } + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + var deltas = new List> + { + delta + }; + + await SaveCustomFieldValues(auditUserDetails, deltas, cancellationToken); + } + + public async Task EditGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossaryItem, CancellationToken cancellationToken) + { + var item = await DatabaseDbContext.Glossaries.FindByGeneralIdRefAsync(new GeneralIdRef { Guid = glossaryItem.Guid, Id = glossaryItem.Id }, cancellationToken); + + if (item != null) + { + item.Name = glossaryItem.Name; + item.Deleted = glossaryItem.Deleted; + } + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.csproj b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.csproj new file mode 100644 index 0000000..cb0afb6 --- /dev/null +++ b/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager/e-suite.Modules.GlossariesManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.GlossariesManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.GlossariesManager/nuget.config b/e-suite.Modules.GlossariesManager/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.GlossariesManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/.gitattributes b/e-suite.Modules.MailTemplatesManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.MailTemplatesManager/.gitignore b/e-suite.Modules.MailTemplatesManager/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/.runsettings b/e-suite.Modules.MailTemplatesManager/.runsettings new file mode 100644 index 0000000..e0fd691 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/README.md b/e-suite.Modules.MailTemplatesManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/azure-pipelines.yml b/e-suite.Modules.MailTemplatesManager/azure-pipelines.yml new file mode 100644 index 0000000..260517f --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/GetMailTemplateTypesUnitTests.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/GetMailTemplateTypesUnitTests.cs new file mode 100644 index 0000000..fab3f10 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/GetMailTemplateTypesUnitTests.cs @@ -0,0 +1,39 @@ +using e_suite.Modules.MailTemplatesManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using eSuite.Core.MailService; +using NUnit.Framework; + +namespace e_suite.Modules.MailTemplatesManager.UnitTests; + +[TestFixture] +public class GetMailTemplateTypesUnitTests : MailTemplatesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetMailTemplateTypes_WhenCalled_ReturnsListOfTypes() + { + //Arrange + var paging = new Paging(); + + //Act + var results = await MailTemplateManager.GetMailTemplateTypes(paging, CancellationToken.None); + + //Assert + Assert.That(results, Is.Not.Null); + Assert.That(results.Count, Is.EqualTo(Enum.GetValues(typeof(MailType)).Length)); + + Assert.That(results.Data, Is.Not.Null); + Assert.That(results.Data.Count(), Is.EqualTo(results.Count)); + + foreach (var item in results.Data) + { + Assert.That(item.MailType, Is.Not.Null); + Assert.That(string.IsNullOrWhiteSpace(item.Description), Is.False); + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/GetMailTemplateUnitTest.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/GetMailTemplateUnitTest.cs new file mode 100644 index 0000000..5fd5c5b --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/GetMailTemplateUnitTest.cs @@ -0,0 +1,138 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Mail; +using e_suite.Modules.MailTemplatesManager.UnitTests.Helpers; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.MailTemplatesManager.UnitTests; + +[TestFixture] +public class GetMailTemplateUnitTest : MailTemplatesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetMailTemplate_WhenDomainMissing_ThrowsException() + { + //Arrange + var domain = new GeneralIdRef + { + Guid = new Guid("9e6665ba-f38b-4051-9cdd-3d981859efb7") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var template = await MailTemplateManager.GetMailTemplate(domain, MailType.ConfirmEmailAddress, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Unable to find domain")); + } + + [Test] + public void GetMailTemplate_MailTemplateDoesNotExist_ThrowsNotFoundException() + { + //Arrange + var domain = new GeneralIdRef + { + Guid = new Guid("9e6665ba-f38b-4051-9cdd-3d981859efb7") + }; + + var dbDomain = new Domain + { + Id = 100, + Guid = domain.Guid.Value, + Name = "Testing domain" + }; + + DomainRepositoryMock.Setup(x => x.GetDomainById(domain, It.IsAny())).ReturnsAsync(dbDomain); + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var template = await MailTemplateManager.GetMailTemplate(domain, MailType.ConfirmEmailAddress, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Unable to find mail template")); + } + + [Test] + public async Task GetMailTemplate_MailTemplateFoundForDomain_ReturnsDomainMailTemplate() + { + //Arrange + var dbDomain = new Domain + { + Id = 100, + Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"), + Name = "Testing domain" + }; + + var domain = new GeneralIdRef + { + Guid = dbDomain.Guid + }; + + var domainMailTemplate = new MailTemplate + { + MailType = MailType.ConfirmEmailAddress, + Subject = "Confirm Email Address (Domain level)", + TemplateDefinition = "This is the message Content" + }; + + DomainRepositoryMock.Setup(x => x.GetDomainById(domain, It.IsAny())).ReturnsAsync(dbDomain); + MailTemplatesManagerRepositoryMock.Setup(x => + x.GetMailTemplate(dbDomain.Id, MailType.ConfirmEmailAddress, It.IsAny())).ReturnsAsync(domainMailTemplate); + + //Act + var template = await MailTemplateManager.GetMailTemplate(domain, MailType.ConfirmEmailAddress, CancellationToken.None); + + //Assert + Assert.That(template.IsOverridden, Is.True); + Assert.That(template.Subject, Is.EqualTo(domainMailTemplate.Subject)); + Assert.That(template.TemplateDefinition, Is.EqualTo(domainMailTemplate.TemplateDefinition)); + } + + [Test] + public async Task GetMailTemplate_MailTemplateFoundForDomain_ReturnsSystemMailTemplate() + { + //Arrange + var dbDomain = new Domain + { + Id = 100, + Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"), + Name = "Testing domain" + }; + + var domain = new GeneralIdRef + { + Guid = dbDomain.Guid + }; + + var systemMailTemplate = new MailTemplate + { + MailType = MailType.ConfirmEmailAddress, + Subject = "Confirm Email Address (System level)", + TemplateDefinition = "This is the message Content" + }; + + DomainRepositoryMock.Setup(x => x.GetDomainById(domain, It.IsAny())).ReturnsAsync(dbDomain); + MailTemplatesManagerRepositoryMock.Setup(x => x.GetMailTemplate(1, MailType.ConfirmEmailAddress, It.IsAny())).ReturnsAsync(systemMailTemplate); + + //Act + var template = await MailTemplateManager.GetMailTemplate(domain, MailType.ConfirmEmailAddress, CancellationToken.None); + + //Assert + Assert.That(template.IsOverridden, Is.False); + Assert.That(template.Subject, Is.EqualTo(systemMailTemplate.Subject)); + Assert.That(template.TemplateDefinition, Is.EqualTo(systemMailTemplate.TemplateDefinition)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/Helpers/MailTemplatesManagerTestBase.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/Helpers/MailTemplatesManagerTestBase.cs new file mode 100644 index 0000000..39b42dd --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/Helpers/MailTemplatesManagerTestBase.cs @@ -0,0 +1,24 @@ +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.UnitTestCore; +using Moq; + +namespace e_suite.Modules.MailTemplatesManager.UnitTests.Helpers; + +public class MailTemplatesManagerTestBase : TestBase +{ + protected Mock MailTemplatesManagerRepositoryMock = null!; + protected Mock DomainRepositoryMock = null!; + protected IMailTemplateManager MailTemplateManager = null!; + + public override async Task Setup() + { + await base.Setup(); + + MailTemplatesManagerRepositoryMock = new Mock(); + DomainRepositoryMock = new Mock(); + + MailTemplateManager = + new MailTemplateManager(MailTemplatesManagerRepositoryMock.Object, DomainRepositoryMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/PostMailTemplateUnitTests.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/PostMailTemplateUnitTests.cs new file mode 100644 index 0000000..5d7840b --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/PostMailTemplateUnitTests.cs @@ -0,0 +1,180 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Mail; +using e_suite.Modules.MailTemplatesManager.UnitTests.Helpers; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.MailTemplatesManager.UnitTests; + +[TestFixture] +public class PostMailTemplateUnitTests : MailTemplatesManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void PostMailTemplate_WhenDomainNotExisting_ThrowNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 666, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var postMailTemplate = new PostMailTemplate() + { + + }; + + //Assert + var actualResult = Assert.ThrowsAsync( + //Act + async () => await MailTemplateManager.PostMailTemplate(postMailTemplate, auditUserDetails, CancellationToken.None)); + + Assert.That(actualResult!.Message, Is.EqualTo("Unable to find domain")); + } + + [Test] + public async Task PostMailTemplate_DomainFoundAndTemplateNotFound_InsertsMailTemplate() + { + //Arrange + var dbDomain = new Domain + { + Id = 100, + Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"), + Name = "Testing domain" + }; + + DomainRepositoryMock.Setup(x => x.GetDomainById(It.IsAny(), It.IsAny())) + .ReturnsAsync(dbDomain); + + var auditUserDetails = new AuditUserDetails + { + UserId = 666, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var postMailTemplate = new PostMailTemplate + { + MailType = MailType.ConfirmEmailAddress, + Subject = "This is the subject", + TemplateDefinition = "This is an email template", + Domain = new GeneralIdRef + { + Id = dbDomain.Id, + Guid = dbDomain.Guid + } + }; + + MailTemplate actualMailTemplate = null!; + AuditUserDetails actualauditUserDetail = null!; + + MailTemplatesManagerRepositoryMock + .Setup(x => x.InsertMailTemplateAsync(It.IsAny(), auditUserDetails, + It.IsAny())).Callback( + (mailtemplate, auditUserDetails, cancellationToken) => + { + actualMailTemplate = mailtemplate; + actualauditUserDetail = auditUserDetails; + }); + + //Act + await MailTemplateManager.PostMailTemplate(postMailTemplate, auditUserDetails, CancellationToken.None); + + //Assert + MailTemplatesManagerRepositoryMock.Verify( + x => x.InsertMailTemplateAsync(It.IsAny(), auditUserDetails, It.IsAny()), + Times.Once); + Assert.That(actualauditUserDetail, Is.Not.Null); + Assert.That(actualMailTemplate, Is.Not.Null); + Assert.That(actualMailTemplate.Subject, Is.EqualTo(postMailTemplate.Subject)); + Assert.That(actualMailTemplate.TemplateDefinition, Is.EqualTo(postMailTemplate.TemplateDefinition)); + Assert.That(actualMailTemplate.DomainId, Is.EqualTo(postMailTemplate.Domain.Id)); + Assert.That(actualMailTemplate.MailType, Is.EqualTo(postMailTemplate.MailType)); + } + + [Test] + public async Task PostMailTemplate_TemplateExists_UpdatesExistingTemplate() + { + //Arrange + var dbDomain = new Domain + { + Id = 100, + Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"), + Name = "Testing domain" + }; + + DomainRepositoryMock.Setup(x => x.GetDomainById(It.IsAny(), It.IsAny())) + .ReturnsAsync(dbDomain); + + var auditUserDetails = new AuditUserDetails + { + UserId = 666, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var postMailTemplate = new PostMailTemplate + { + MailType = MailType.ConfirmEmailAddress, + Subject = "This is the subject", + TemplateDefinition = "This is an email template", + Domain = new GeneralIdRef + { + Id = dbDomain.Id, + Guid = dbDomain.Guid + } + }; + + var domainMailTemplate = new MailTemplate + { + DomainId = 100, + Domain = dbDomain, + MailType = MailType.ConfirmEmailAddress, + Subject = "Confirm Email Address (Domain level)", + TemplateDefinition = "This is the message Content" + }; + + MailTemplatesManagerRepositoryMock.Setup(x => + x.GetMailTemplate(dbDomain.Id, MailType.ConfirmEmailAddress, It.IsAny())).ReturnsAsync(domainMailTemplate); + + + MailTemplate actualMailTemplate = null!; + AuditUserDetails actualauditUserDetail = null!; + MailTemplatesManagerRepositoryMock + .Setup(x => x.UpdateMailTemplateAsync(It.IsAny(), auditUserDetails, + It.IsAny())).Callback( + (mailtemplate, auditUserDetails, cancellationToken) => + { + actualMailTemplate = mailtemplate; + actualauditUserDetail = auditUserDetails; + }); + + //Act + await MailTemplateManager.PostMailTemplate(postMailTemplate, auditUserDetails, CancellationToken.None); + + //Assert + MailTemplatesManagerRepositoryMock.Verify( + x => x.InsertMailTemplateAsync(It.IsAny(), auditUserDetails, It.IsAny()), + Times.Never); + + + Assert.That(actualauditUserDetail, Is.Not.Null); + Assert.That(actualMailTemplate, Is.Not.Null); + Assert.That(actualMailTemplate.Subject, Is.EqualTo(postMailTemplate.Subject)); + Assert.That(actualMailTemplate.TemplateDefinition, Is.EqualTo(postMailTemplate.TemplateDefinition)); + Assert.That(actualMailTemplate.DomainId, Is.EqualTo(postMailTemplate.Domain.Id)); + Assert.That(actualMailTemplate.MailType, Is.EqualTo(postMailTemplate.MailType)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/e-suite.Modules.MailTemplatesManager.UnitTests.csproj b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/e-suite.Modules.MailTemplatesManager.UnitTests.csproj new file mode 100644 index 0000000..287f2e9 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.UnitTests/e-suite.Modules.MailTemplatesManager.UnitTests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + e_suite.Modules.MailTemplatesManager.UnitTests + enable + enable + + + + + + + + + + + + + + diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.sln b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.sln new file mode 100644 index 0000000..a2798c9 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.MailTemplatesManager", "e-suite.Modules.MailTemplatesManager\e-suite.Modules.MailTemplatesManager.csproj", "{3526A514-CF86-4352-9A85-EEF52A298313}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{130F399D-DAC5-4AD5-BAD8-B32F2D15145F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{86F9467C-A929-4F7E-9F0C-98DD3BB49E45}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Modules.MailTemplatesManager.UnitTests", "e-suite.Modules.MailTemplatesManager.UnitTests\e-suite.Modules.MailTemplatesManager.UnitTests.csproj", "{471DE465-39B0-43E9-94FF-E7FA012CA360}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3526A514-CF86-4352-9A85-EEF52A298313}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3526A514-CF86-4352-9A85-EEF52A298313}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3526A514-CF86-4352-9A85-EEF52A298313}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3526A514-CF86-4352-9A85-EEF52A298313}.Release|Any CPU.Build.0 = Release|Any CPU + {471DE465-39B0-43E9-94FF-E7FA012CA360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {471DE465-39B0-43E9-94FF-E7FA012CA360}.Debug|Any CPU.Build.0 = Debug|Any CPU + {471DE465-39B0-43E9-94FF-E7FA012CA360}.Release|Any CPU.ActiveCfg = Release|Any CPU + {471DE465-39B0-43E9-94FF-E7FA012CA360}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {86F9467C-A929-4F7E-9F0C-98DD3BB49E45} = {130F399D-DAC5-4AD5-BAD8-B32F2D15145F} + {471DE465-39B0-43E9-94FF-E7FA012CA360} = {86F9467C-A929-4F7E-9F0C-98DD3BB49E45} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D168BE55-6CB5-42EA-95CB-A6D5A9860F8D} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.v3.ncrunchsolution b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/GlobalSuppressions.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/GlobalSuppressions.cs new file mode 100644 index 0000000..9633a17 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/IocRegistration.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/IocRegistration.cs new file mode 100644 index 0000000..39fafc8 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.MailTemplatesManager.repository; + +namespace e_suite.Modules.MailTemplatesManager; + +public class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/MailTemplateManager.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/MailTemplateManager.cs new file mode 100644 index 0000000..aa88407 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/MailTemplateManager.cs @@ -0,0 +1,132 @@ +using e_suite.Utilities.Pagination; +using eSuite.Core.MailService; +using System.ComponentModel.DataAnnotations; +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using e_suite.Database.Core.Tables.Mail; +using MockQueryable; + +namespace e_suite.Modules.MailTemplatesManager; + +public class MailTemplateManager : IMailTemplateManager +{ + private readonly IDomainRepository _domainRepository; + private readonly IMailTemplatesManagerRepository _mailTemplatesManagerRepository; + const long sunStrategyDomainId = 1; + + public MailTemplateManager(IMailTemplatesManagerRepository mailTemplatesManagerRepository, IDomainRepository domainRepository) + { + _mailTemplatesManagerRepository = mailTemplatesManagerRepository; + _domainRepository = domainRepository; + } + + public async Task> GetMailTemplateTypes(Paging paging, CancellationToken cancellationToken) + { + var mailTemplateTypes = new List(); + + foreach (var mailtype in Enum.GetValues()) + { + mailTemplateTypes.Add( new MailTemplateType + { + MailType = mailtype, + Description = GetEnumDisplayName(mailtype) + }); + } + + var queriableMailTemplateTypes = mailTemplateTypes.BuildMock(); + + var paginatedResult = await PaginatedData.Paginate(queriableMailTemplateTypes, paging, KeySelector, FilterSelector, + cancellationToken); + + return paginatedResult; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "description" => x => x.Description!.Contains(value), + "mailtype" => x => x.MailType.ToString().Contains(value), + _ => x => x.MailType.ToString().Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "description" => x => x.Description!, + "mailtype" => x => x.MailType, + _ => x => x.MailType + }; + } + + public static string? GetEnumDisplayName(Enum value) + { + var fieldInfo = value.GetType().GetField(value.ToString()); + + if (fieldInfo?.GetCustomAttributes(typeof(DisplayAttribute), false) is DisplayAttribute[] attributes && attributes.Length > 0) + { + return attributes.First().Name; + } + + return value.ToString(); + } + + public async Task GetMailTemplate(IGeneralIdRef domainId, MailType mailType, CancellationToken cancellationToken) + { + var domain = await _domainRepository.GetDomainById(domainId, cancellationToken) ?? throw new NotFoundException($"Unable to find domain"); + + var isOverridden = true; + var mailTemplate = await _mailTemplatesManagerRepository.GetMailTemplate(domain.Id, mailType, cancellationToken); + + if (mailTemplate == null) + { + isOverridden = false; + mailTemplate = + await _mailTemplatesManagerRepository.GetMailTemplate(sunStrategyDomainId, mailType, + cancellationToken); + } + + if (mailTemplate is null) + throw new NotFoundException("Unable to find mail template"); + + return new GetMailTemplate + { + IsOverridden = isOverridden, + Subject = mailTemplate!.Subject, + TemplateDefinition = mailTemplate.TemplateDefinition + }; + } + + public async Task PostMailTemplate(PostMailTemplate mailTemplate, AuditUserDetails auditUserDetails, CancellationToken cancellationToken) + { + var domain = await _domainRepository.GetDomainById(mailTemplate.Domain, cancellationToken) ?? throw new NotFoundException($"Unable to find domain"); + + var template = await _mailTemplatesManagerRepository.GetMailTemplate(domain.Id, mailTemplate.MailType, cancellationToken); + if (template == null) + { + template = new MailTemplate + { + DomainId = domain.Id, + MailType = mailTemplate.MailType, + Subject = mailTemplate.Subject, + TemplateDefinition = mailTemplate.TemplateDefinition + }; + + await _mailTemplatesManagerRepository.InsertMailTemplateAsync(template, auditUserDetails, cancellationToken); + } + else + { + template.Subject = mailTemplate.Subject; + template.TemplateDefinition = mailTemplate.TemplateDefinition; + + await _mailTemplatesManagerRepository.UpdateMailTemplateAsync(template, auditUserDetails, cancellationToken); + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.csproj b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.csproj new file mode 100644 index 0000000..daa446d --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.MailTemplatesManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/repository/MailTemplatesManagerRepository.cs b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/repository/MailTemplatesManagerRepository.cs new file mode 100644 index 0000000..623f125 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/e-suite.Modules.MailTemplatesManager/repository/MailTemplatesManagerRepository.cs @@ -0,0 +1,35 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Mail; +using eSuite.Core.MailService; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.MailTemplatesManager.repository; + +public class MailTemplatesManagerRepository : RepositoryBase, IMailTemplatesManagerRepository +{ + public MailTemplatesManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public async Task GetMailTemplate(long domainId, MailType emailRequestEmailType, CancellationToken cancellationToken) + { + return await DatabaseDbContext.MailTemplates.SingleOrDefaultAsync(x => + !x.Deleted && x.DomainId == domainId && x.MailType == emailRequestEmailType, cancellationToken); + } + + public async Task InsertMailTemplateAsync(MailTemplate template, AuditUserDetails auditUserDetails, + CancellationToken cancellationToken) + { + await DatabaseDbContext.MailTemplates.AddAsync(template); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task UpdateMailTemplateAsync(MailTemplate template, AuditUserDetails auditUserDetails, + CancellationToken cancellationToken) + { + DatabaseDbContext.MailTemplates.Update(template); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.MailTemplatesManager/nuget.config b/e-suite.Modules.MailTemplatesManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.MailTemplatesManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/.gitattributes b/e-suite.Modules.OrganisationManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.OrganisationManager/.gitignore b/e-suite.Modules.OrganisationManager/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Modules.OrganisationManager/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/.runsettings b/e-suite.Modules.OrganisationManager/.runsettings new file mode 100644 index 0000000..e0fd691 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/README.md b/e-suite.Modules.OrganisationManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/azure-pipelines.yml b/e-suite.Modules.OrganisationManager/azure-pipelines.yml new file mode 100644 index 0000000..29158cc --- /dev/null +++ b/e-suite.Modules.OrganisationManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-Suite.Modules.OrganisationsManager/e-Suite.Modules.OrganisationsManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/CreateOrganisationUnitTests.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/CreateOrganisationUnitTests.cs new file mode 100644 index 0000000..a499ae3 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/CreateOrganisationUnitTests.cs @@ -0,0 +1,101 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Modules.OrganisationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.OrganisationManager.UnitTests; + +[TestFixture] +public class CreateOrganisationUnitTests : OrganisationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task AddOrganisation_WhenGuidAlreadyExists_ThrowsArgumentException() + { + // Arrange + var organisation1 = new CreateOrganisation + { + Guid = new Guid("f215fefc-369a-4d83-a8eb-8de7cf3e4539"), + Name = "Sun Strategy", + Address = "London, United Kingdom", + Status = OrganisationStatus.Active + }; + + await OrganisationManager.AddOrganisation(AuditUserDetails, organisation1, true, default); + + var organisation2 = new CreateOrganisation + { + Guid = organisation1.Guid, + Name = "Microsoft", + Address = "Mountain View, USA", + Status = OrganisationStatus.Active + }; + + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + await OrganisationManager.AddOrganisation(AuditUserDetails, organisation2, true, default); + }); + } + + [Test] + public async Task AddOrganisation_WhenOrganisationNameAlreadyExists_ThrowsArgumentException() + { + // Arrange + var organisation1 = new CreateOrganisation + { + Guid = new Guid("34c3320d-0625-4f93-ad21-b98ada6b1270"), + Name = "Sun Strategy", + Address = "London, United Kingdom", + Status = OrganisationStatus.Active + }; + + await OrganisationManager.AddOrganisation(AuditUserDetails, organisation1, true, default); + + var organisation2 = new CreateOrganisation + { + Guid = new Guid("60b46146-bd8a-4c0e-ad0f-eb939970b394"), + Name = organisation1.Name, + Address = "Mountain View, USA", + Status = OrganisationStatus.Active + }; + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + await OrganisationManager.AddOrganisation(AuditUserDetails, organisation2, true, default); + }); + } + + [Test] + public async Task AddOrganisation_WhenNotDuplicates_CreatesOrfanisation() + { + // Arrange + var organisation = new CreateOrganisation + { + Guid = new Guid("0f493204-052a-4b66-ac5d-e4621edddd9a"), + Name = "Sun Strategy", + Address = "London, United Kingdom", + Status = OrganisationStatus.Active + }; + + // Act + await OrganisationManager.AddOrganisation(AuditUserDetails, organisation, true, default); + + // Assert + var result = await OrganisationManager.GetOrganisation(new GeneralIdRef { Guid = organisation.Guid }, default); + Assert.That(result, Is.Not.Null); + Assert.That(result.Name, Is.EqualTo(organisation.Name)); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/DeleteOrganisationUnitTests.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/DeleteOrganisationUnitTests.cs new file mode 100644 index 0000000..4804213 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/DeleteOrganisationUnitTests.cs @@ -0,0 +1,92 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.OrganisationManager.UnitTests.Helpers; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.OrganisationManager.UnitTests; + +[TestFixture] +public class DeleteOrganisationUnitTests : OrganisationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ShouldDeleteOrganisationHierarcy() + { + // Arrange + var organisation = new Organisation + { + Id = 999, + Guid = new Guid("7305c943-0552-492b-a31a-5f458eba04d7"), + Name = "Sun Strategy", + Address = "London, United Kindom", + Status = OrganisationStatus.Active, + Deleted = false, + }; + + var site = new Site + { + Id = 888, + Guid = new Guid("907e808f-b099-47b3-8f0b-7a9e236d2206"), + Name = "Sun Strategy Printing 1", + Address = "Bristol, UK", + Status = OrganisationStatus.Active, + Deleted = false, + OrganisationId = organisation.Id + }; + + var specification = new Specification + { + Id = 777, + Guid = new Guid("ca5fd7ae-53a8-45e4-91ce-6c10243ea027"), + Name = "Litho printing", + Deleted = false, + SiteId = site.Id + }; + + FakeOrganisationManagerRepository.Organisations.Add(organisation); + FakeOrganisationManagerRepository.Sites.Add(site); + FakeOrganisationManagerRepository.Specifications.Add(specification); + + // Act + await OrganisationManager.DeleteOrganisation(AuditUserDetails, organisation.ToGeneralIdRef()!, true, default); + + // Assert + Assert.Multiple(() => + { + Assert.That(FakeOrganisationManagerRepository.Organisations[0].Deleted, Is.True); + Assert.That(FakeOrganisationManagerRepository.Sites[0].Deleted, Is.True); + Assert.That(FakeOrganisationManagerRepository.Specifications[0].Deleted, Is.True); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + }); + } + + [Test] + public void ShouldThrowException_GlossaryNotFound() + { + // Arrange + var organisation = new Organisation + { + Id = 999, + Guid = new Guid("bc9ec2c0-b988-4d38-980b-b7fbea878d62"), + Name = "Sun Strategy", + Address = "London, United Kindom", + Status = OrganisationStatus.Active, + Deleted = false, + }; + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + await OrganisationManager.DeleteOrganisation(AuditUserDetails, organisation.ToGeneralIdRef()!, true, default); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/EditOrganisationUnitTests.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/EditOrganisationUnitTests.cs new file mode 100644 index 0000000..9ca0692 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/EditOrganisationUnitTests.cs @@ -0,0 +1,73 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.OrganisationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.OrganisationManager.UnitTests; + +[TestFixture] +public class EditOrganisationUnitTests : OrganisationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ShouldEditOrganisation() + { + // Arrange + var organisation = new Organisation + { + Id = 999, + Guid = Guid.NewGuid(), + Name = "Sun Strategy", + Address = "Bristol, United Kindom", + Status = OrganisationStatus.Active, + Deleted = false, + }; + + FakeOrganisationManagerRepository.Organisations.Add(organisation); + + var editedOrganisation = new EditOrganisation + { + GeneralIdRef = new GeneralIdRef { Id = 999, Guid = organisation.Guid }, + Name = "Sun Solutions", + Address = "London, United Kingdom", + Status = OrganisationStatus.Pending, + }; + + // Act + await OrganisationManager.EditOrganisation(AuditUserDetails, editedOrganisation, true, default); + var result = await OrganisationManager.GetOrganisation(new GeneralIdRef { Id = 999, Guid = organisation.Guid }, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Name, Is.EqualTo(editedOrganisation.Name)); + Assert.That(result.Address, Is.EqualTo(editedOrganisation.Address)); + Assert.That(result.Status, Is.EqualTo(editedOrganisation.Status)); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + } + + [Test] + public void ShouldThrowException_GlossaryNotFound() + { + // Arrange + var editedOrganisation = new EditOrganisation + { + GeneralIdRef = new GeneralIdRef { Id = 999, Guid = Guid.NewGuid() }, + Name = "Sun Solutions", + Address = "London, United Kingdom", + Status = OrganisationStatus.Pending, + }; + + // Act + // Assert + Assert.ThrowsAsync(async () => { await OrganisationManager.EditOrganisation(AuditUserDetails, editedOrganisation, true, default); }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/GetOrganisationListUnitTests.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/GetOrganisationListUnitTests.cs new file mode 100644 index 0000000..ceec94c --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/GetOrganisationListUnitTests.cs @@ -0,0 +1,71 @@ +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.OrganisationManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.OrganisationManager.UnitTests; + +[TestFixture] +public class GetOrganisationListUnitTests : OrganisationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ShouldReturnOrganisationsList() + { + // Arrange + var organisation1 = new Organisation + { + Id = 1, + Guid = Guid.NewGuid(), + Name = "Sun Strategy", + Address = "London, United Kingdom", + Status = OrganisationStatus.Active + }; + + var organisation2 = new Organisation + { + Id = 2, + Guid = Guid.NewGuid(), + Name = "Microsoft", + Address = "Mountain View, USA", + Status = OrganisationStatus.Active + }; + + var organisation3 = new Organisation + { + Id = 3, + Guid = Guid.NewGuid(), + Name = "Twitter", + Address = "Mountain View, USA", + Status = OrganisationStatus.Active, + Deleted = true + }; + + FakeOrganisationManagerRepository.Organisations.Add(organisation1); + FakeOrganisationManagerRepository.Organisations.Add(organisation2); + FakeOrganisationManagerRepository.Organisations.Add(organisation3); + + var paging = new Paging() + { + Page = 1, + PageSize = 10, + SortAscending = true, + Filters = string.Empty + }; + + // Act + var result = await OrganisationManager.GetOrganisationList(paging, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result.Data, Is.Not.Null); + Assert.That(result.Data.Count, Is.EqualTo(2)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/Helpers/OrganisationManagerTestBase.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/Helpers/OrganisationManagerTestBase.cs new file mode 100644 index 0000000..d0a3a95 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/Helpers/OrganisationManagerTestBase.cs @@ -0,0 +1,32 @@ +using e_suite.API.Common; +using e_suite.Database.Audit; +using e_suite.Messaging.Common; +using e_suite.Modules.OrganisationManager.UnitTests.Repository; +using e_suite.UnitTestCore; +using Moq; + +namespace e_suite.Modules.OrganisationManager.UnitTests.Helpers; + +public class OrganisationManagerTestBase : TestBase +{ + protected FakeOrganisationManagerRepository FakeOrganisationManagerRepository = null!; + protected AuditUserDetails AuditUserDetails = null!; + protected Mock EFlowSyncMessageSenderMock = null!; + protected IOrganisationsManager OrganisationManager = null!; + + public override async Task Setup() + { + await base.Setup(); + + AuditUserDetails = new AuditUserDetails + { + UserId = -1, + UserDisplayName = "Testing User", + Comment = "Test comment" + }; + + FakeOrganisationManagerRepository = new FakeOrganisationManagerRepository(); + EFlowSyncMessageSenderMock = new Mock(); + OrganisationManager = new OrganisationsManager.OrganisationsManager(FakeOrganisationManagerRepository, EFlowSyncMessageSenderMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/Repository/FakeOrganisationManagerRepository.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/Repository/FakeOrganisationManagerRepository.cs new file mode 100644 index 0000000..5562e41 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/Repository/FakeOrganisationManagerRepository.cs @@ -0,0 +1,64 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.OrganisationManager.UnitTests.Repository; + +public class FakeOrganisationManagerRepository : FakeRepository, IOrganisationsManagerRepository +{ + public List Organisations = []; + public List Sites = []; + public List Specifications = []; + + public FakeOrganisationManagerRepository() + { + + } + + public IQueryable GetOrganisationsList() + { + return Organisations.Where(x => x.Deleted == false).ToList().BuildMock(); + } + + public Task AddOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken) + { + Organisations.Add(organisation); + return Task.CompletedTask; + } + + public Task FindOrganisation(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(Organisations.FindByGeneralIdRef(generalIdRef)); + } + + public Task DeleteOrganisation(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var organisation = Organisations.FindByGeneralIdRef(generalIdRef); + + if (organisation != null) + { + organisation.Deleted = true; + var sites = Sites.Where(x => x.OrganisationId == organisation.Id).ToList(); + + foreach (var site in sites) + { + site.Deleted = true; + + var specs = Specifications.Where(x => x.SiteId == site.Id).ToList(); + specs.ForEach(x => x.Deleted = true); + } + } + + return Task.CompletedTask; + } + + public Task EditOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/e-suite.Modules.OrganisationsManager.UnitTests.csproj b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/e-suite.Modules.OrganisationsManager.UnitTests.csproj new file mode 100644 index 0000000..5fa29e9 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationManger.UnitTests/e-suite.Modules.OrganisationsManager.UnitTests.csproj @@ -0,0 +1,31 @@ + + + + net10.0 + enable + enable + e_suite.Modules.OrganisationManager.UnitTests + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.sln b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.sln new file mode 100644 index 0000000..acd2f69 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32929.385 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{1C41E5C8-A3D5-4B70-AEFB-622BFEB54DB8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{011DB9E4-CA9F-42F3-8BA0-FC87352AB22C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.OrganisationsManager.UnitTests", "e-Suite.Modules.OrganisationManger.UnitTests\e-suite.Modules.OrganisationsManager.UnitTests.csproj", "{4BCFFB75-5BCE-4845-808C-417054BF11AD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.OrganisationsManager", "e-Suite.Modules.OrganisationsManager\e-suite.Modules.OrganisationsManager.csproj", "{4CE41083-3C47-4DD1-A3D7-683E19B56DB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4BCFFB75-5BCE-4845-808C-417054BF11AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BCFFB75-5BCE-4845-808C-417054BF11AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BCFFB75-5BCE-4845-808C-417054BF11AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BCFFB75-5BCE-4845-808C-417054BF11AD}.Release|Any CPU.Build.0 = Release|Any CPU + {4CE41083-3C47-4DD1-A3D7-683E19B56DB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CE41083-3C47-4DD1-A3D7-683E19B56DB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CE41083-3C47-4DD1-A3D7-683E19B56DB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CE41083-3C47-4DD1-A3D7-683E19B56DB0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {011DB9E4-CA9F-42F3-8BA0-FC87352AB22C} = {1C41E5C8-A3D5-4B70-AEFB-622BFEB54DB8} + {4BCFFB75-5BCE-4845-808C-417054BF11AD} = {011DB9E4-CA9F-42F3-8BA0-FC87352AB22C} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {413F3899-EA93-4235-8E56-B291E3516F61} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.sln.DotSettings b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.sln.DotSettings new file mode 100644 index 0000000..7eae05c --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.sln.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.v3.ncrunchsolution b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/GlobalSuppressions.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/GlobalSuppressions.cs new file mode 100644 index 0000000..9633a17 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/IocRegistration.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/IocRegistration.cs new file mode 100644 index 0000000..d3b8199 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.OrganisationsManager.Repository; + +namespace e_suite.Modules.OrganisationsManager; + +public class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/OrganisationsManager.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/OrganisationsManager.cs new file mode 100644 index 0000000..2fc5900 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/OrganisationsManager.cs @@ -0,0 +1,133 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; +using e_suite.Utilities.Pagination; +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Messaging.Common; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.OrganisationsManager; + +public class OrganisationsManager : IOrganisationsManager +{ + private readonly IOrganisationsManagerRepository _organisationsManagerRepository; + private readonly IEFlowSyncMessageSender _eFlowSyncMessageSender; + + public OrganisationsManager(IOrganisationsManagerRepository organisationsManagerRepository, IEFlowSyncMessageSender eFlowSyncMessageSender) + { + _organisationsManagerRepository = organisationsManagerRepository; + _eFlowSyncMessageSender = eFlowSyncMessageSender; + } + + public async Task GetOrganisation(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await _organisationsManagerRepository.FindOrganisation(generalIdRef, cancellationToken); + } + + public async Task AddOrganisation(AuditUserDetails auditUserDetails, CreateOrganisation addOrganisationDto, bool triggerEFlowSync, CancellationToken cancellationToken) + { + await _organisationsManagerRepository.TransactionAsync(async () => + { + var duplicateGuid = addOrganisationDto.Guid == null ? null : await _organisationsManagerRepository.FindOrganisation(new GeneralIdRef { Guid = addOrganisationDto.Guid }, cancellationToken); + if (duplicateGuid != null) + throw new ArgumentException($"Guid {addOrganisationDto.Guid} is already used."); + + if (await _organisationsManagerRepository.GetOrganisationsList().FirstOrDefaultAsync( x => x.Name == addOrganisationDto.Name, cancellationToken) != null) + throw new ArgumentException($"{addOrganisationDto.Name} is already used."); + + var organisation = new Organisation + { + Guid = addOrganisationDto.Guid ?? Guid.NewGuid(), + Name = addOrganisationDto.Name, + Address = addOrganisationDto.Address, + Status = addOrganisationDto.Status + }; + + await _organisationsManagerRepository.AddOrganisation(auditUserDetails, organisation, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + }); + } + + public async Task> GetOrganisationList( Paging paging, CancellationToken cancellationToken ) + { + var organisations = _organisationsManagerRepository.GetOrganisationsList(); + + var paginatedData = await PaginatedData.Paginate(organisations, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(x => new ReadOrganisation + { + Guid = x.Guid, + Id = x.Id, + Name = x.Name, + Address = x.Address, + Status = x.Status, + }) + }; + return paginatedResult; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "name" => x => x.Name.Contains(value), + "address" => x => x.Address.Contains(value), + "status" => x => x.Status.ToString().ToLower().Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "name" => x => x.Name, + "address" => x => x.Address, + "status" => x => x.Status.ToString().ToLower(), + _ => x => x.Name + }; + } + + public async Task DeleteOrganisation(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, bool triggerEFlowSync, CancellationToken cancellationToken) + { + var existingOrganisation = await _organisationsManagerRepository.FindOrganisation(generalIdRef, cancellationToken); + + if (existingOrganisation == null) + throw new NotFoundException("Organisation with this Id was not foud."); + + await _organisationsManagerRepository.DeleteOrganisation(auditUserDetails, generalIdRef, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + } + + public async Task EditOrganisation(AuditUserDetails auditUserDetails, EditOrganisation editOrganisationDto, bool triggerEFlowSync, CancellationToken cancellationToken) + { + var existingOrganisation = await _organisationsManagerRepository.FindOrganisation(editOrganisationDto.GeneralIdRef, cancellationToken); + + if (existingOrganisation == null) + throw new NotFoundException("Organisation with this Id was not foud."); + + existingOrganisation.Name = editOrganisationDto.Name; + existingOrganisation.Address = editOrganisationDto.Address; + existingOrganisation.Status = editOrganisationDto.Status; + + await _organisationsManagerRepository.EditOrganisation(auditUserDetails, existingOrganisation, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/Repository/OrganisationsManagerRepository.cs b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/Repository/OrganisationsManagerRepository.cs new file mode 100644 index 0000000..0001cf2 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/Repository/OrganisationsManagerRepository.cs @@ -0,0 +1,59 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.OrganisationsManager.Repository; + +public class OrganisationsManagerRepository : RepositoryBase, IOrganisationsManagerRepository +{ + public OrganisationsManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetOrganisationsList() + { + return DatabaseDbContext.Organisations.Where(x => x.Deleted == false); + } + + public async Task FindOrganisation(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Organisations.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task AddOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken) + { + await DatabaseDbContext.Organisations.AddAsync(organisation, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteOrganisation(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var organisation = await DatabaseDbContext.Organisations.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + + if (organisation != null) + { + organisation.Deleted = true; + var sites = await DatabaseDbContext.Sites.Where(x => x.OrganisationId == organisation.Id).ToListAsync(cancellationToken); + + foreach (var site in sites) + { + site.Deleted = true; + + var specs = await DatabaseDbContext.Specifications.Where(x => x.SiteId == site.Id).ToListAsync(cancellationToken); + specs.ForEach(x => x.Deleted = true); + } + } + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken) + { + DatabaseDbContext.Organisations.Update(organisation); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/e-suite.Modules.OrganisationsManager.csproj b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/e-suite.Modules.OrganisationsManager.csproj new file mode 100644 index 0000000..3503dfb --- /dev/null +++ b/e-suite.Modules.OrganisationManager/e-Suite.Modules.OrganisationsManager/e-suite.Modules.OrganisationsManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.OrganisationsManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.OrganisationManager/nuget.config b/e-suite.Modules.OrganisationManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.OrganisationManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.sln b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.sln new file mode 100644 index 0000000..8f9f5af --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.API.Common", "..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj", "{81076865-C1A1-481F-8575-3B885D3E2815}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "eSuite.API", "..\e-suite.API\eSuite.API\eSuite.API.csproj", "{6B63DFDE-B215-494E-A1D6-3A866BF9C910}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.PerformanceManager", "e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager.csproj", "{68D84134-021E-424E-BB07-1E43156D3294}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {81076865-C1A1-481F-8575-3B885D3E2815}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81076865-C1A1-481F-8575-3B885D3E2815}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81076865-C1A1-481F-8575-3B885D3E2815}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81076865-C1A1-481F-8575-3B885D3E2815}.Release|Any CPU.Build.0 = Release|Any CPU + {6B63DFDE-B215-494E-A1D6-3A866BF9C910}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B63DFDE-B215-494E-A1D6-3A866BF9C910}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B63DFDE-B215-494E-A1D6-3A866BF9C910}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B63DFDE-B215-494E-A1D6-3A866BF9C910}.Release|Any CPU.Build.0 = Release|Any CPU + {68D84134-021E-424E-BB07-1E43156D3294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68D84134-021E-424E-BB07-1E43156D3294}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68D84134-021E-424E-BB07-1E43156D3294}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68D84134-021E-424E-BB07-1E43156D3294}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {835D9105-6EA7-4293-B272-6A0E908E4350} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.v3.ncrunchsolution.user b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.v3.ncrunchsolution.user new file mode 100644 index 0000000..b82f7a5 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.v3.ncrunchsolution.user @@ -0,0 +1,5 @@ + + + Run all tests automatically [Global] + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/GlobalSuppressions.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3114c6e --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructor fields are not readonly", Scope = "member", Target = "~M:e_suite.Modules.PerformanceManager.PerformanceManager.#ctor(e_suite.API.Common.repository.IPerformanceManagerRepository)")] diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/IocRegistration.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/IocRegistration.cs new file mode 100644 index 0000000..cbc7d89 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.DiagnosticManager.repository; + +namespace e_suite.Modules.PerformanceManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/PerformanceManager.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/PerformanceManager.cs new file mode 100644 index 0000000..c4dc7fb --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/PerformanceManager.cs @@ -0,0 +1,154 @@ +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Tables.Diagnostics; +using e_suite.Utilities.Pagination; + +namespace e_suite.Modules.PerformanceManager; + +public class PerformanceManager : IPerformanceManager +{ + private readonly IPerformanceManagerRepository _performanceManagerRepository; + + public PerformanceManager(IPerformanceManagerRepository performanceManagerRepository) + { + _performanceManagerRepository = performanceManagerRepository; + } + + public async Task> GetPerformanceSummaryAsync(Paging paging, CancellationToken cancellationToken) + { + var performanceReportSummary = _performanceManagerRepository.GetPerformanceReportSummary(); + + + var paginatedData = await PaginatedData.Paginate(performanceReportSummary, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(ToReadPerformanceReportSummary) + + }; + + return paginatedResult; + } + + private ReadPerformanceReportSummary ToReadPerformanceReportSummary(PerformanceReportSummary performanceReportSummary) + { + return new ReadPerformanceReportSummary(performanceReportSummary) + { + Host = performanceReportSummary.Host, + ControllerName = performanceReportSummary.ControllerName, + ActionName = performanceReportSummary.ActionName + }; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "host" => x => x.Host.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "controllername" => x => x.ControllerName.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "actionname" => x => x.ActionName.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "requestType" => x => x.RequestType.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "count" => x => x.Count.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "mintotaltimems" => x => x.MinTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "maxtotaltimemS" => x => x.MaxTotalTimeMS.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "avgtotaltimems" => x => x.AvgTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "sumtotaltimems" => x => x.SumTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + _ => x => x.SumTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "host" => x => x.Host, + "controllername" => x => x.ControllerName, + "actionname" => x => x.ActionName, + "requestType" => x => x.RequestType, + "count" => x => x.Count, + "mintotaltimems" => x => x.MinTotalTimeMs, + "maxtotaltimemS" => x => x.MaxTotalTimeMS, + "avgtotaltimems" => x => x.AvgTotalTimeMs, + "sumtotaltimems" => x => x.SumTotalTimeMs, + _ => x => x.SumTotalTimeMs + }; + } + + public async Task> GetPerformanceDetailsAsync( + string hostName, + string controllerName, + string actionName, + string requestType, + Paging paging, + CancellationToken cancellationToken + ) + { + var performanceReportSummary = _performanceManagerRepository.GetPerformanceReports(hostName, controllerName, actionName, requestType); + + var paginatedData = await PaginatedData.Paginate(performanceReportSummary, paging, + PerformanceReportKeySelector, PerformanceReportFilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(ToReadPerformanceReport) + + }; + + return paginatedResult; + } + + private ReadPerformanceReport ToReadPerformanceReport(PerformanceReport report) + { + return new ReadPerformanceReport(report) + { + Host = report.Host, + ControllerName = report.ControllerName, + ActionName = report.ActionName + }; + } + + private Expression> PerformanceReportKeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "host" => x => x.Host, + "controllername" => x => x.ControllerName, + "actionname" => x => x.ActionName, + "requestType" => x => x.RequestType, + "id" => x => x.Id, + "actionparameters" => x => x.ActionParameters, + "startdateyime" => x => x.StartDateTime, + "timings" => x => x.Timings, + "totaltimems" => x => x.TotalTimeMS, + _ => x => x.StartDateTime + }; + } + + private Expression> PerformanceReportFilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "host" => x => x.Host.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "controllername" => x => x.ControllerName.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "actionname" => x => x.ActionName.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "requestType" => x => x.RequestType.Contains(value, StringComparison.CurrentCultureIgnoreCase), + "id" => x => x.Id.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "actionparameters" => x => + x.ActionParameters.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "startdateyime" => x => + x.StartDateTime.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "timings" => x => x.Timings.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + "totaltimems" => x => x.TotalTimeMS.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase), + _ => x => x.StartDateTime.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase) + }; + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.API.Common.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.API.Common.dll new file mode 100644 index 0000000..f1483da Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.API.Common.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.API.Common.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.API.Common.pdb new file mode 100644 index 0000000..d449c6f Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.API.Common.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Audit.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Audit.dll new file mode 100644 index 0000000..0c1a5a5 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Audit.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Audit.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Audit.pdb new file mode 100644 index 0000000..331774c Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Audit.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Core.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Core.dll new file mode 100644 index 0000000..3739327 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Core.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Core.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Core.pdb new file mode 100644 index 0000000..c4bf7bf Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Database.Core.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.deps.json b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.deps.json new file mode 100644 index 0000000..865a545 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.deps.json @@ -0,0 +1,216 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v10.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v10.0": { + "e-suite.Modules.PerformanceManager/1.0.0": { + "dependencies": { + "Autofac": "9.0.0", + "e-suite.API.Common": "1.0.0", + "e-suite.Utilities.Pagination": "1.0.0", + "e-suite.Nuget.PasswordHasher": "1.0.0.0" + }, + "runtime": { + "e-suite.Modules.PerformanceManager.dll": {} + } + }, + "Autofac/9.0.0": { + "runtime": { + "lib/net10.0/Autofac.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.0.0" + } + } + }, + "Microsoft.EntityFrameworkCore/10.0.2": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "10.0.2" + }, + "runtime": { + "lib/net10.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "10.0.2.0", + "fileVersion": "10.0.225.61305" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/10.0.2": { + "runtime": { + "lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "10.0.2.0", + "fileVersion": "10.0.225.61305" + } + } + }, + "Newtonsoft.Json/13.0.4": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.4.30916" + } + } + }, + "System.Linq.Dynamic.Core/1.7.1": { + "runtime": { + "lib/net10.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.7.1.0", + "fileVersion": "1.7.1.0" + } + } + }, + "e-suite.API.Common/1.0.0": { + "dependencies": { + "e-suite.Database.Core": "1.0.0", + "e-suite.Utilities.Pagination": "1.0.0" + }, + "runtime": { + "e-suite.API.Common.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Audit/1.0.0": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "10.0.2", + "Newtonsoft.Json": "13.0.4", + "System.Linq.Dynamic.Core": "1.7.1", + "eSuite.Core": "1.0.0" + }, + "runtime": { + "e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/1.0.0": { + "dependencies": { + "e-suite.Database.Audit": "1.0.0", + "eSuite.Core": "1.0.0", + "e_suite.Nuget.PasswordHasher": "1.0.0" + }, + "runtime": { + "e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/1.0.0": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "10.0.2" + }, + "runtime": { + "e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/1.0.0": { + "runtime": { + "eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/1.0.0": { + "runtime": { + "e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Nuget.PasswordHasher/1.0.0.0": { + "runtime": { + "e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "e-suite.Modules.PerformanceManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Autofac/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-G8TpUMVIq1pEAMuAao8h5MKduY91SotjgK93wQb5LaxbJUVE0/XjCA6t2SOp+AkPC3GB/C2MAiF2D7krYjraFw==", + "path": "autofac/9.0.0", + "hashPath": "autofac.9.0.0.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/10.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-d3+XKbLSHPCu3vwpXECoXcFbvGKmAhEeUmc1xy2czmuPnEF7rZN2HP5ZGMwCMbAKk4B01+nS4HixSMo2Vf/Y9g==", + "path": "microsoft.entityframeworkcore/10.0.2", + "hashPath": "microsoft.entityframeworkcore.10.0.2.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/10.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-BzAwIU5mYeOmnKbEXrkwx7feW2V+zUTrK/kRonSib94tjvc0/iRj2a4N6YGXRhTNjaFP3tvCMIDaX1vIFF6dkg==", + "path": "microsoft.entityframeworkcore.abstractions/10.0.2", + "hashPath": "microsoft.entityframeworkcore.abstractions.10.0.2.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-pdgNNMai3zv51W5aq268sujXUyx7SNdE2bj1wZcWjAQrKMFZV260lbqYop1d2GM67JI1huLRwxo9ZqnfF/lC6A==", + "path": "newtonsoft.json/13.0.4", + "hashPath": "newtonsoft.json.13.0.4.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.7.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qlgku/j9r0fei52yxR5ho9nC/fWGZuaELqPkZmJm24QZbBW4cL3sVWri1dZ0cKgARD7cgFKBdRqzxYoIG5Q0Cg==", + "path": "system.linq.dynamic.core/1.7.1", + "hashPath": "system.linq.dynamic.core.1.7.1.nupkg.sha512" + }, + "e-suite.API.Common/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e-suite.Database.Audit/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e-suite.Database.Core/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e-suite.Utilities.Pagination/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "eSuite.Core/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e_suite.Nuget.PasswordHasher/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "e-suite.Nuget.PasswordHasher/1.0.0.0": { + "type": "reference", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..efdad25 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.pdb new file mode 100644 index 0000000..d89ea39 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Modules.PerformanceManager.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Nuget.PasswordHasher.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Nuget.PasswordHasher.dll new file mode 100644 index 0000000..b9e7562 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Nuget.PasswordHasher.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Nuget.PasswordHasher.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Nuget.PasswordHasher.pdb new file mode 100644 index 0000000..3b511f7 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Nuget.PasswordHasher.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Utilities.Pagination.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Utilities.Pagination.dll new file mode 100644 index 0000000..4a5b408 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Utilities.Pagination.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Utilities.Pagination.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Utilities.Pagination.pdb new file mode 100644 index 0000000..efee26f Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/e-suite.Utilities.Pagination.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.dll new file mode 100644 index 0000000..537d423 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.dll.config b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.dll.config new file mode 100644 index 0000000..b430050 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.dll.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.pdb new file mode 100644 index 0000000..dbcfb9e Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net10.0/eSuite.Core.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.API.Common.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.API.Common.dll new file mode 100644 index 0000000..c8c78da Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.API.Common.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.API.Common.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.API.Common.pdb new file mode 100644 index 0000000..f086c2e Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.API.Common.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.deps.json b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.deps.json new file mode 100644 index 0000000..15864ca --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.deps.json @@ -0,0 +1,361 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "e-suite.Modules.DiagnosticManager/1.0.0": { + "dependencies": { + "Autofac": "8.0.0", + "e-suite.API.Common": "1.0.0", + "e-suite.Utilities.Pagination": "2024.1.4.2" + }, + "runtime": { + "e-suite.Modules.DiagnosticManager.dll": {} + } + }, + "Autofac/8.0.0": { + "dependencies": { + "System.Diagnostics.DiagnosticSource": "7.0.2" + }, + "runtime": { + "lib/net8.0/Autofac.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.0.0" + } + } + }, + "e-suite.Database.Audit/2024.2.12.4": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "8.0.1", + "Newtonsoft.Json": "13.0.3", + "System.Linq.Dynamic.Core": "1.3.8", + "eSuite.Core": "2024.2.12.3" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/2024.2.12.7": { + "dependencies": { + "e-suite.Database.Audit": "2024.2.12.4", + "e_suite.Nuget.PasswordHasher": "2024.1.4.2" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/2024.1.4.2": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "8.0.1" + }, + "runtime": { + "lib/net8.0/e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/2024.2.12.3": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.1" + }, + "runtime": { + "lib/net8.0/eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/2024.1.4.2": { + "runtime": { + "lib/net8.0/e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.EntityFrameworkCore/8.0.1": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "8.0.1", + "Microsoft.EntityFrameworkCore.Analyzers": "8.0.1", + "Microsoft.Extensions.Caching.Memory": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "8.0.1.0", + "fileVersion": "8.0.123.58002" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/8.0.1": { + "runtime": { + "lib/net8.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "8.0.1.0", + "fileVersion": "8.0.123.58002" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/8.0.1": {}, + "Microsoft.Extensions.Caching.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder/8.0.1": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Binder.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.123.58001" + } + } + }, + "Microsoft.Extensions.DependencyInjection/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": {}, + "Microsoft.Extensions.Logging/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.Options/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Primitives/8.0.0": {}, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Diagnostics.DiagnosticSource/7.0.2": {}, + "System.Linq.Dynamic.Core/1.3.8": { + "runtime": { + "lib/net8.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.3.8.0", + "fileVersion": "1.3.8.0" + } + } + }, + "e-suite.API.Common/1.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "8.0.1", + "e-suite.Database.Core": "2024.2.12.7", + "e-suite.Utilities.Pagination": "2024.1.4.2", + "eSuite.Core": "2024.2.12.3" + }, + "runtime": { + "e-suite.API.Common.dll": {} + } + } + } + }, + "libraries": { + "e-suite.Modules.DiagnosticManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Autofac/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qxVqJcl3fixxa5aZc9TmIuYTwooI9GCL5RzfUiTZtTlbAF3NcWz7bPeEyJEAyS/0qGhSyGnXeku2eiu/7L+3qw==", + "path": "autofac/8.0.0", + "hashPath": "autofac.8.0.0.nupkg.sha512" + }, + "e-suite.Database.Audit/2024.2.12.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FV60dJ/9LzSaTj1lp1+vxMxFeZwdBbnlBl3MnaVJNpiTBug6VzcphQ/CrgWxFkG5omV37AlAeDVE1M8NS5MNkw==", + "path": "e-suite.database.audit/2024.2.12.4", + "hashPath": "e-suite.database.audit.2024.2.12.4.nupkg.sha512" + }, + "e-suite.Database.Core/2024.2.12.7": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eGLlBkTkzy4vbwgPy0wdcgQdUN3Z2y9iH1/8NCgZkHrewXNUZcHhlCfRtFVXtaxy+43BOHl14StYkPgCQJ6F0Q==", + "path": "e-suite.database.core/2024.2.12.7", + "hashPath": "e-suite.database.core.2024.2.12.7.nupkg.sha512" + }, + "e-suite.Utilities.Pagination/2024.1.4.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ernGjn9PxuAr0MeE3tUWMRPNzm8A5WkVumkTWKBIrN+9WqzEhN5yccKaJFXkzOpCA4Jb5A0h89njewwzQz7LEg==", + "path": "e-suite.utilities.pagination/2024.1.4.2", + "hashPath": "e-suite.utilities.pagination.2024.1.4.2.nupkg.sha512" + }, + "eSuite.Core/2024.2.12.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KHpPM53v0QYNAEDKly2prWAMgpJGgwDooIWXMOwwoxTFwPSRD31NVESAB78flKKwvf4NWT7HvyTS0wekGEPjaw==", + "path": "esuite.core/2024.2.12.3", + "hashPath": "esuite.core.2024.2.12.3.nupkg.sha512" + }, + "e_suite.Nuget.PasswordHasher/2024.1.4.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FAXAX9FMp/vFI1Ct3uF0fWzfXtTQ7ez7lpJyIz908q8SGpIIcvh+S3EQujI1CIulsSiRzqN7w11/Zb2Kdr4hQA==", + "path": "e_suite.nuget.passwordhasher/2024.1.4.2", + "hashPath": "e_suite.nuget.passwordhasher.2024.1.4.2.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hPagYIuWPpZF6AwOR7mlKv+GLEk8wrbsIVr8qYHqSWN2zDghOYTu2Qxi6CtrJP3V9UgzZ6sjQVM/jnrodpz10Q==", + "path": "microsoft.entityframeworkcore/8.0.1", + "hashPath": "microsoft.entityframeworkcore.8.0.1.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KBj2meUDWmMDRYpxyebyYQMf7+aGyTWvKD9UTuFKPP/NQGVsJUqbCCM+p/LCxSppcm2dQt+z73e/yBFlq/2jmA==", + "path": "microsoft.entityframeworkcore.abstractions/8.0.1", + "hashPath": "microsoft.entityframeworkcore.abstractions.8.0.1.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-8HgodfPiUEMu5rlkcGa9CJdEpF5VeaeWhHAdKuKstgr6GBFc91xCJo/haOVzM8jKPS167PrlC8ChYdtzFVpp4A==", + "path": "microsoft.entityframeworkcore.analyzers/8.0.1", + "hashPath": "microsoft.entityframeworkcore.analyzers.8.0.1.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==", + "path": "microsoft.extensions.caching.abstractions/8.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7pqivmrZDzo1ADPkRwjy+8jtRKWRCPag9qPI+p7sgu7Q4QreWhcvbiWXsbhP+yY8XSiDvZpu2/LWdBv7PnmOpQ==", + "path": "microsoft.extensions.caching.memory/8.0.0", + "hashPath": "microsoft.extensions.caching.memory.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Binder/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2UKFJnLiBt7Od6nCnTqP9rTIUNhzmn9Hv1l2FchyKbz8xieB9ULwZTbQZMw+M24Qw3F5dzzH1U9PPleN0LNLOQ==", + "path": "microsoft.extensions.configuration.binder/8.0.1", + "hashPath": "microsoft.extensions.configuration.binder.8.0.1.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", + "path": "microsoft.extensions.dependencyinjection/8.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==", + "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", + "path": "microsoft.extensions.logging/8.0.0", + "hashPath": "microsoft.extensions.logging.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "path": "microsoft.extensions.logging.abstractions/8.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", + "path": "microsoft.extensions.options/8.0.0", + "hashPath": "microsoft.extensions.options.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Diagnostics.DiagnosticSource/7.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hYr3I9N9811e0Bjf2WNwAGGyTuAFbbTgX1RPLt/3Wbm68x3IGcX5Cl75CMmgT6WlNwLQ2tCCWfqYPpypjaf2xA==", + "path": "system.diagnostics.diagnosticsource/7.0.2", + "hashPath": "system.diagnostics.diagnosticsource.7.0.2.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.3.8": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qEBOJO6z4Ps8HE4EM3S0tvBnshgE6mpTd7sv2kAdHaMNkIRIZ+dttvaC9NnL5SFN8maHEvsW0h2xJ7X0Vp9b6Q==", + "path": "system.linq.dynamic.core/1.3.8", + "hashPath": "system.linq.dynamic.core.1.3.8.nupkg.sha512" + }, + "e-suite.API.Common/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.dll new file mode 100644 index 0000000..44f327b Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.pdb new file mode 100644 index 0000000..f2d5703 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.DiagnosticManager.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.deps.json b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.deps.json new file mode 100644 index 0000000..e420c63 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.deps.json @@ -0,0 +1,361 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "e-suite.Modules.PerformanceManager/1.0.0": { + "dependencies": { + "Autofac": "8.0.0", + "e-suite.API.Common": "1.0.0", + "e-suite.Utilities.Pagination": "2024.1.4.2" + }, + "runtime": { + "e-suite.Modules.PerformanceManager.dll": {} + } + }, + "Autofac/8.0.0": { + "dependencies": { + "System.Diagnostics.DiagnosticSource": "7.0.2" + }, + "runtime": { + "lib/net8.0/Autofac.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.0.0" + } + } + }, + "e-suite.Database.Audit/2024.2.12.4": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "8.0.1", + "Newtonsoft.Json": "13.0.3", + "System.Linq.Dynamic.Core": "1.3.8", + "eSuite.Core": "2024.2.12.3" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Audit.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Database.Core/2024.2.12.7": { + "dependencies": { + "e-suite.Database.Audit": "2024.2.12.4", + "e_suite.Nuget.PasswordHasher": "2024.1.4.2" + }, + "runtime": { + "lib/net8.0/e-suite.Database.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e-suite.Utilities.Pagination/2024.1.4.2": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "8.0.1" + }, + "runtime": { + "lib/net8.0/e-suite.Utilities.Pagination.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "eSuite.Core/2024.2.12.3": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.1" + }, + "runtime": { + "lib/net8.0/eSuite.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "e_suite.Nuget.PasswordHasher/2024.1.4.2": { + "runtime": { + "lib/net8.0/e-suite.Nuget.PasswordHasher.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.EntityFrameworkCore/8.0.1": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "8.0.1", + "Microsoft.EntityFrameworkCore.Analyzers": "8.0.1", + "Microsoft.Extensions.Caching.Memory": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "8.0.1.0", + "fileVersion": "8.0.123.58002" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/8.0.1": { + "runtime": { + "lib/net8.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "8.0.1.0", + "fileVersion": "8.0.123.58002" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/8.0.1": {}, + "Microsoft.Extensions.Caching.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder/8.0.1": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Binder.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.123.58001" + } + } + }, + "Microsoft.Extensions.DependencyInjection/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": {}, + "Microsoft.Extensions.Logging/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.Options/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Primitives/8.0.0": {}, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Diagnostics.DiagnosticSource/7.0.2": {}, + "System.Linq.Dynamic.Core/1.3.8": { + "runtime": { + "lib/net8.0/System.Linq.Dynamic.Core.dll": { + "assemblyVersion": "1.3.8.0", + "fileVersion": "1.3.8.0" + } + } + }, + "e-suite.API.Common/1.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "8.0.1", + "e-suite.Database.Core": "2024.2.12.7", + "e-suite.Utilities.Pagination": "2024.1.4.2", + "eSuite.Core": "2024.2.12.3" + }, + "runtime": { + "e-suite.API.Common.dll": {} + } + } + } + }, + "libraries": { + "e-suite.Modules.PerformanceManager/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Autofac/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qxVqJcl3fixxa5aZc9TmIuYTwooI9GCL5RzfUiTZtTlbAF3NcWz7bPeEyJEAyS/0qGhSyGnXeku2eiu/7L+3qw==", + "path": "autofac/8.0.0", + "hashPath": "autofac.8.0.0.nupkg.sha512" + }, + "e-suite.Database.Audit/2024.2.12.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FV60dJ/9LzSaTj1lp1+vxMxFeZwdBbnlBl3MnaVJNpiTBug6VzcphQ/CrgWxFkG5omV37AlAeDVE1M8NS5MNkw==", + "path": "e-suite.database.audit/2024.2.12.4", + "hashPath": "e-suite.database.audit.2024.2.12.4.nupkg.sha512" + }, + "e-suite.Database.Core/2024.2.12.7": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eGLlBkTkzy4vbwgPy0wdcgQdUN3Z2y9iH1/8NCgZkHrewXNUZcHhlCfRtFVXtaxy+43BOHl14StYkPgCQJ6F0Q==", + "path": "e-suite.database.core/2024.2.12.7", + "hashPath": "e-suite.database.core.2024.2.12.7.nupkg.sha512" + }, + "e-suite.Utilities.Pagination/2024.1.4.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ernGjn9PxuAr0MeE3tUWMRPNzm8A5WkVumkTWKBIrN+9WqzEhN5yccKaJFXkzOpCA4Jb5A0h89njewwzQz7LEg==", + "path": "e-suite.utilities.pagination/2024.1.4.2", + "hashPath": "e-suite.utilities.pagination.2024.1.4.2.nupkg.sha512" + }, + "eSuite.Core/2024.2.12.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KHpPM53v0QYNAEDKly2prWAMgpJGgwDooIWXMOwwoxTFwPSRD31NVESAB78flKKwvf4NWT7HvyTS0wekGEPjaw==", + "path": "esuite.core/2024.2.12.3", + "hashPath": "esuite.core.2024.2.12.3.nupkg.sha512" + }, + "e_suite.Nuget.PasswordHasher/2024.1.4.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FAXAX9FMp/vFI1Ct3uF0fWzfXtTQ7ez7lpJyIz908q8SGpIIcvh+S3EQujI1CIulsSiRzqN7w11/Zb2Kdr4hQA==", + "path": "e_suite.nuget.passwordhasher/2024.1.4.2", + "hashPath": "e_suite.nuget.passwordhasher.2024.1.4.2.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hPagYIuWPpZF6AwOR7mlKv+GLEk8wrbsIVr8qYHqSWN2zDghOYTu2Qxi6CtrJP3V9UgzZ6sjQVM/jnrodpz10Q==", + "path": "microsoft.entityframeworkcore/8.0.1", + "hashPath": "microsoft.entityframeworkcore.8.0.1.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KBj2meUDWmMDRYpxyebyYQMf7+aGyTWvKD9UTuFKPP/NQGVsJUqbCCM+p/LCxSppcm2dQt+z73e/yBFlq/2jmA==", + "path": "microsoft.entityframeworkcore.abstractions/8.0.1", + "hashPath": "microsoft.entityframeworkcore.abstractions.8.0.1.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-8HgodfPiUEMu5rlkcGa9CJdEpF5VeaeWhHAdKuKstgr6GBFc91xCJo/haOVzM8jKPS167PrlC8ChYdtzFVpp4A==", + "path": "microsoft.entityframeworkcore.analyzers/8.0.1", + "hashPath": "microsoft.entityframeworkcore.analyzers.8.0.1.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==", + "path": "microsoft.extensions.caching.abstractions/8.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7pqivmrZDzo1ADPkRwjy+8jtRKWRCPag9qPI+p7sgu7Q4QreWhcvbiWXsbhP+yY8XSiDvZpu2/LWdBv7PnmOpQ==", + "path": "microsoft.extensions.caching.memory/8.0.0", + "hashPath": "microsoft.extensions.caching.memory.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Binder/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2UKFJnLiBt7Od6nCnTqP9rTIUNhzmn9Hv1l2FchyKbz8xieB9ULwZTbQZMw+M24Qw3F5dzzH1U9PPleN0LNLOQ==", + "path": "microsoft.extensions.configuration.binder/8.0.1", + "hashPath": "microsoft.extensions.configuration.binder.8.0.1.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", + "path": "microsoft.extensions.dependencyinjection/8.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==", + "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", + "path": "microsoft.extensions.logging/8.0.0", + "hashPath": "microsoft.extensions.logging.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "path": "microsoft.extensions.logging.abstractions/8.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", + "path": "microsoft.extensions.options/8.0.0", + "hashPath": "microsoft.extensions.options.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Diagnostics.DiagnosticSource/7.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hYr3I9N9811e0Bjf2WNwAGGyTuAFbbTgX1RPLt/3Wbm68x3IGcX5Cl75CMmgT6WlNwLQ2tCCWfqYPpypjaf2xA==", + "path": "system.diagnostics.diagnosticsource/7.0.2", + "hashPath": "system.diagnostics.diagnosticsource.7.0.2.nupkg.sha512" + }, + "System.Linq.Dynamic.Core/1.3.8": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qEBOJO6z4Ps8HE4EM3S0tvBnshgE6mpTd7sv2kAdHaMNkIRIZ+dttvaC9NnL5SFN8maHEvsW0h2xJ7X0Vp9b6Q==", + "path": "system.linq.dynamic.core/1.3.8", + "hashPath": "system.linq.dynamic.core.1.3.8.nupkg.sha512" + }, + "e-suite.API.Common/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..7426f65 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.pdb new file mode 100644 index 0000000..8e0cefe Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/bin/Debug/net8.0/e-suite.Modules.PerformanceManager.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.csproj b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.csproj new file mode 100644 index 0000000..cb2163f --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.PerformanceManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/.NETCoreApp,Version=v10.0.AssemblyAttributes.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/.NETCoreApp,Version=v10.0.AssemblyAttributes.cs new file mode 100644 index 0000000..925b135 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/.NETCoreApp,Version=v10.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v10.0", FrameworkDisplayName = ".NET 10.0")] diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite..A86FA394.Up2Date b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite..A86FA394.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.AssemblyInfo.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.AssemblyInfo.cs new file mode 100644 index 0000000..3e0da47 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-suite.Modules.PerformanceManager")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-suite.Modules.PerformanceManager")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-suite.Modules.PerformanceManager")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache new file mode 100644 index 0000000..5a191a2 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +0f662bdafe7384dbd4340094b9eed6c2b3726486e827df695766cc0a48949cea diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..a7d2438 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,17 @@ +is_global = true +build_property.TargetFramework = net10.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v10.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_suite.Modules.PerformanceManager +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 10.0 +build_property.EnableCodeStyleSeverity = diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.GlobalUsings.g.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.GlobalUsings.g.cs new file mode 100644 index 0000000..d12bcbc --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.assets.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.assets.cache new file mode 100644 index 0000000..4df1df9 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.assets.cache differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache new file mode 100644 index 0000000..39fe2ee Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..0fbdfc5 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +2443ebba828e75681ac0f97ca7de8f4489ebb89e56b84c10c1343a75554c6876 diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.FileListAbsolute.txt b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..6d88b99 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.csproj.FileListAbsolute.txt @@ -0,0 +1,26 @@ +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Modules.PerformanceManager.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Modules.PerformanceManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Modules.PerformanceManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.API.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Database.Audit.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Database.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Nuget.PasswordHasher.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Utilities.Pagination.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\eSuite.Core.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.API.Common.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Utilities.Pagination.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Database.Audit.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Database.Core.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\eSuite.Core.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\eSuite.Core.dll.config +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net10.0\e-suite.Nuget.PasswordHasher.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite..A86FA394.Up2Date +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\refint\e-suite.Modules.PerformanceManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\e-suite.Modules.PerformanceManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net10.0\ref\e-suite.Modules.PerformanceManager.dll diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..efdad25 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.pdb new file mode 100644 index 0000000..d89ea39 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/e-suite.Modules.PerformanceManager.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/ref/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/ref/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..5bd0b41 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/ref/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/refint/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/refint/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..5bd0b41 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net10.0/refint/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite..96D46AEF.Up2Date b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite..96D46AEF.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite..A86FA394.Up2Date b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite..A86FA394.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.AssemblyInfo.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.AssemblyInfo.cs new file mode 100644 index 0000000..29b3b83 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-suite.Modules.DiagnosticManager")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-suite.Modules.DiagnosticManager")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-suite.Modules.DiagnosticManager")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.AssemblyInfoInputs.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.AssemblyInfoInputs.cache new file mode 100644 index 0000000..69687f1 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +ec74d7603f4e899f876c3ef8df7489e184503ee6e786b412fe2c2c97028faa83 diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..fa86f8e --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_suite.Modules.DiagnosticManager +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.GlobalUsings.g.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.assets.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.assets.cache new file mode 100644 index 0000000..73ae1f9 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.assets.cache differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.AssemblyReference.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.AssemblyReference.cache new file mode 100644 index 0000000..2b44b56 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.CoreCompileInputs.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..c424eb8 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +26427db4030e6bc8dbc57ea4427d4b6123ddc9d03d64dbeffe8a185e82bd6b8c diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.FileListAbsolute.txt b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..b819641 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.csproj.FileListAbsolute.txt @@ -0,0 +1,15 @@ +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\bin\Debug\net8.0\e-suite.Modules.DiagnosticManager.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\bin\Debug\net8.0\e-suite.Modules.DiagnosticManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\bin\Debug\net8.0\e-suite.Modules.DiagnosticManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\bin\Debug\net8.0\e-suite.API.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\bin\Debug\net8.0\e-suite.API.Common.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite..96D46AEF.Up2Date +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\refint\e-suite.Modules.DiagnosticManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\e-suite.Modules.DiagnosticManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.DiagnosticManager\e-suite.Modules.DiagnosticManager\obj\Debug\net8.0\ref\e-suite.Modules.DiagnosticManager.dll diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.dll new file mode 100644 index 0000000..44f327b Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.pdb new file mode 100644 index 0000000..f2d5703 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.DiagnosticManager.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.AssemblyInfo.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.AssemblyInfo.cs new file mode 100644 index 0000000..3e0da47 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("e-suite.Modules.PerformanceManager")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("e-suite.Modules.PerformanceManager")] +[assembly: System.Reflection.AssemblyTitleAttribute("e-suite.Modules.PerformanceManager")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache new file mode 100644 index 0000000..5a191a2 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +0f662bdafe7384dbd4340094b9eed6c2b3726486e827df695766cc0a48949cea diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..1915b94 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,17 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = e_suite.Modules.PerformanceManager +build_property.ProjectDir = C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.GlobalUsings.g.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.GlobalUsings.g.cs new file mode 100644 index 0000000..d12bcbc --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.assets.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.assets.cache new file mode 100644 index 0000000..ad0f817 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.assets.cache differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache new file mode 100644 index 0000000..609ac96 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..6283be7 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +2f9e9e25b27809ab4a5dd84cc789593e5f468064ea9fb1ce42520be1628cd733 diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.FileListAbsolute.txt b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..cac47ef --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.csproj.FileListAbsolute.txt @@ -0,0 +1,15 @@ +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net8.0\e-suite.Modules.PerformanceManager.deps.json +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net8.0\e-suite.Modules.PerformanceManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net8.0\e-suite.Modules.PerformanceManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net8.0\e-suite.API.Common.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\bin\Debug\net8.0\e-suite.API.Common.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.csproj.AssemblyReference.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.AssemblyInfoInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.AssemblyInfo.cs +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.csproj.CoreCompileInputs.cache +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite..A86FA394.Up2Date +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\refint\e-suite.Modules.PerformanceManager.dll +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\e-suite.Modules.PerformanceManager.pdb +C:\Users\me\OneDrive\Code\Sun\e-suite\e-suite.Modules.PerformanceManager\e-suite.Modules.PerformanceManager\obj\Debug\net8.0\ref\e-suite.Modules.PerformanceManager.dll diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..7426f65 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.pdb b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.pdb new file mode 100644 index 0000000..8e0cefe Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/e-suite.Modules.PerformanceManager.pdb differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/ref/e-suite.Modules.DiagnosticManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/ref/e-suite.Modules.DiagnosticManager.dll new file mode 100644 index 0000000..f8d1c51 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/ref/e-suite.Modules.DiagnosticManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/ref/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/ref/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..ce06a8c Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/ref/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/refint/e-suite.Modules.DiagnosticManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/refint/e-suite.Modules.DiagnosticManager.dll new file mode 100644 index 0000000..f8d1c51 Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/refint/e-suite.Modules.DiagnosticManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/refint/e-suite.Modules.PerformanceManager.dll b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/refint/e-suite.Modules.PerformanceManager.dll new file mode 100644 index 0000000..ce06a8c Binary files /dev/null and b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/Debug/net8.0/refint/e-suite.Modules.PerformanceManager.dll differ diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.dgspec.json b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.dgspec.json new file mode 100644 index 0000000..4b15c30 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.dgspec.json @@ -0,0 +1,176 @@ +{ + "format": 1, + "restore": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager.csproj": {} + }, + "projects": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj", + "projectName": "e-suite.API.Common", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": { + "target": "Package", + "version": "[8.0.1, )" + }, + "e-suite.Database.Core": { + "target": "Package", + "version": "[2024.2.12.7, )" + }, + "e-suite.Utilities.Pagination": { + "target": "Package", + "version": "[2024.1.4.2, )" + }, + "eSuite.Core": { + "target": "Package", + "version": "[2024.2.12.3, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.202/PortableRuntimeIdentifierGraph.json" + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager.csproj", + "projectName": "e-suite.Modules.DiagnosticManager", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.DiagnosticManager\\e-suite.Modules.DiagnosticManager\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Autofac": { + "target": "Package", + "version": "[8.0.0, )" + }, + "e-suite.API.Common": { + "target": "Package", + "version": "[2024.2.13.3, )" + }, + "e-suite.Utilities.Pagination": { + "target": "Package", + "version": "[2024.1.4.2, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.202/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.g.props b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.g.props new file mode 100644 index 0000000..c6034bb --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.g.props @@ -0,0 +1,19 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\me\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages + PackageReference + 6.9.1 + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.g.targets b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.g.targets new file mode 100644 index 0000000..f2d2c3b --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.DiagnosticManager.csproj.nuget.g.targets @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.dgspec.json b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.dgspec.json new file mode 100644 index 0000000..17505ff --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.dgspec.json @@ -0,0 +1,2604 @@ +{ + "format": 1, + "restore": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj": {} + }, + "projects": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj", + "projectName": "e-suite.API.Common", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Core\\e-suite.Database.Core\\e-suite.Database.Core.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Core\\e-suite.Database.Core\\e-suite.Database.Core.csproj" + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": { + "target": "Package", + "version": "[10.0.2, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj", + "projectName": "eSuite.Core", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": { + "target": "Package", + "version": "[10.0.2, )" + }, + "Microsoft.Extensions.Configuration.Binder": { + "target": "Package", + "version": "[10.0.2, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Audit\\e-suite.Database.Audit\\e-suite.Database.Audit.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Audit\\e-suite.Database.Audit\\e-suite.Database.Audit.csproj", + "projectName": "e-suite.Database.Audit", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Audit\\e-suite.Database.Audit\\e-suite.Database.Audit.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Audit\\e-suite.Database.Audit\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj" + } + } + } + }, + "warningProperties": { + "noWarn": [ + "NU1904" + ], + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "dependencies": { + "Microsoft.EntityFrameworkCore": { + "target": "Package", + "version": "[10.0.2, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.4, )" + }, + "System.Linq.Dynamic.Core": { + "target": "Package", + "version": "[1.7.1, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Core\\e-suite.Database.Core\\e-suite.Database.Core.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Core\\e-suite.Database.Core\\e-suite.Database.Core.csproj", + "projectName": "e-suite.Database.Core", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Core\\e-suite.Database.Core\\e-suite.Database.Core.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Core\\e-suite.Database.Core\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Core\\eSuite.Core\\eSuite.Core.csproj" + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Audit\\e-suite.Database.Audit\\e-suite.Database.Audit.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Database.Audit\\e-suite.Database.Audit\\e-suite.Database.Audit.csproj" + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj", + "projectName": "e-suite.Modules.PerformanceManager", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj" + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "dependencies": { + "Autofac": { + "target": "Package", + "version": "[9.0.0, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher.csproj", + "projectName": "e_suite.Nuget.PasswordHasher", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Nuget.PasswordHasher\\e-suite.Nuget.PasswordHasher\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.AspNetCore": "(,10.0.32767]", + "Microsoft.AspNetCore.Antiforgery": "(,10.0.32767]", + "Microsoft.AspNetCore.App": "(,10.0.32767]", + "Microsoft.AspNetCore.Authentication": "(,10.0.32767]", + "Microsoft.AspNetCore.Authentication.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Authentication.BearerToken": "(,10.0.32767]", + "Microsoft.AspNetCore.Authentication.Cookies": "(,10.0.32767]", + "Microsoft.AspNetCore.Authentication.Core": "(,10.0.32767]", + "Microsoft.AspNetCore.Authentication.OAuth": "(,10.0.32767]", + "Microsoft.AspNetCore.Authorization": "(,10.0.32767]", + "Microsoft.AspNetCore.Authorization.Policy": "(,10.0.32767]", + "Microsoft.AspNetCore.Components": "(,10.0.32767]", + "Microsoft.AspNetCore.Components.Authorization": "(,10.0.32767]", + "Microsoft.AspNetCore.Components.Endpoints": "(,10.0.32767]", + "Microsoft.AspNetCore.Components.Forms": "(,10.0.32767]", + "Microsoft.AspNetCore.Components.Server": "(,10.0.32767]", + "Microsoft.AspNetCore.Components.Web": "(,10.0.32767]", + "Microsoft.AspNetCore.Connections.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.CookiePolicy": "(,10.0.32767]", + "Microsoft.AspNetCore.Cors": "(,10.0.32767]", + "Microsoft.AspNetCore.Cryptography.Internal": "(,10.0.32767]", + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "(,10.0.32767]", + "Microsoft.AspNetCore.DataProtection": "(,10.0.32767]", + "Microsoft.AspNetCore.DataProtection.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.DataProtection.Extensions": "(,10.0.32767]", + "Microsoft.AspNetCore.Diagnostics": "(,10.0.32767]", + "Microsoft.AspNetCore.Diagnostics.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Diagnostics.HealthChecks": "(,10.0.32767]", + "Microsoft.AspNetCore.HostFiltering": "(,10.0.32767]", + "Microsoft.AspNetCore.Hosting": "(,10.0.32767]", + "Microsoft.AspNetCore.Hosting.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Hosting.Server.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Html.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Http": "(,10.0.32767]", + "Microsoft.AspNetCore.Http.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Http.Connections": "(,10.0.32767]", + "Microsoft.AspNetCore.Http.Connections.Common": "(,10.0.32767]", + "Microsoft.AspNetCore.Http.Extensions": "(,10.0.32767]", + "Microsoft.AspNetCore.Http.Features": "(,10.0.32767]", + "Microsoft.AspNetCore.Http.Results": "(,10.0.32767]", + "Microsoft.AspNetCore.HttpLogging": "(,10.0.32767]", + "Microsoft.AspNetCore.HttpOverrides": "(,10.0.32767]", + "Microsoft.AspNetCore.HttpsPolicy": "(,10.0.32767]", + "Microsoft.AspNetCore.Identity": "(,10.0.32767]", + "Microsoft.AspNetCore.Localization": "(,10.0.32767]", + "Microsoft.AspNetCore.Localization.Routing": "(,10.0.32767]", + "Microsoft.AspNetCore.Metadata": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.ApiExplorer": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Core": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Cors": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.DataAnnotations": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Formatters.Json": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Formatters.Xml": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Localization": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.Razor": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.RazorPages": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.TagHelpers": "(,10.0.32767]", + "Microsoft.AspNetCore.Mvc.ViewFeatures": "(,10.0.32767]", + "Microsoft.AspNetCore.OutputCaching": "(,10.0.32767]", + "Microsoft.AspNetCore.RateLimiting": "(,10.0.32767]", + "Microsoft.AspNetCore.Razor": "(,10.0.32767]", + "Microsoft.AspNetCore.Razor.Runtime": "(,10.0.32767]", + "Microsoft.AspNetCore.RequestDecompression": "(,10.0.32767]", + "Microsoft.AspNetCore.ResponseCaching": "(,10.0.32767]", + "Microsoft.AspNetCore.ResponseCaching.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.ResponseCompression": "(,10.0.32767]", + "Microsoft.AspNetCore.Rewrite": "(,10.0.32767]", + "Microsoft.AspNetCore.Routing": "(,10.0.32767]", + "Microsoft.AspNetCore.Routing.Abstractions": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.HttpSys": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.IIS": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.IISIntegration": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.Kestrel": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.Kestrel.Core": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.Kestrel.Transport.Quic": "(,10.0.32767]", + "Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets": "(,10.0.32767]", + "Microsoft.AspNetCore.Session": "(,10.0.32767]", + "Microsoft.AspNetCore.SignalR": "(,10.0.32767]", + "Microsoft.AspNetCore.SignalR.Common": "(,10.0.32767]", + "Microsoft.AspNetCore.SignalR.Core": "(,10.0.32767]", + "Microsoft.AspNetCore.SignalR.Protocols.Json": "(,10.0.32767]", + "Microsoft.AspNetCore.StaticAssets": "(,10.0.32767]", + "Microsoft.AspNetCore.StaticFiles": "(,10.0.32767]", + "Microsoft.AspNetCore.WebSockets": "(,10.0.32767]", + "Microsoft.AspNetCore.WebUtilities": "(,10.0.32767]", + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.Extensions.Caching.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Caching.Memory": "(,10.0.32767]", + "Microsoft.Extensions.Configuration": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.Binder": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.CommandLine": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.FileExtensions": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.Ini": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.Json": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.KeyPerFile": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.UserSecrets": "(,10.0.32767]", + "Microsoft.Extensions.Configuration.Xml": "(,10.0.32767]", + "Microsoft.Extensions.DependencyInjection": "(,10.0.32767]", + "Microsoft.Extensions.DependencyInjection.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Diagnostics": "(,10.0.32767]", + "Microsoft.Extensions.Diagnostics.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Diagnostics.HealthChecks": "(,10.0.32767]", + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Features": "(,10.0.32767]", + "Microsoft.Extensions.FileProviders.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.FileProviders.Composite": "(,10.0.32767]", + "Microsoft.Extensions.FileProviders.Physical": "(,10.0.32767]", + "Microsoft.Extensions.FileSystemGlobbing": "(,10.0.32767]", + "Microsoft.Extensions.Hosting": "(,10.0.32767]", + "Microsoft.Extensions.Hosting.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Http": "(,10.0.32767]", + "Microsoft.Extensions.Identity.Core": "(,10.0.32767]", + "Microsoft.Extensions.Identity.Stores": "(,10.0.32767]", + "Microsoft.Extensions.Localization": "(,10.0.32767]", + "Microsoft.Extensions.Localization.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Logging": "(,10.0.32767]", + "Microsoft.Extensions.Logging.Abstractions": "(,10.0.32767]", + "Microsoft.Extensions.Logging.Configuration": "(,10.0.32767]", + "Microsoft.Extensions.Logging.Console": "(,10.0.32767]", + "Microsoft.Extensions.Logging.Debug": "(,10.0.32767]", + "Microsoft.Extensions.Logging.EventLog": "(,10.0.32767]", + "Microsoft.Extensions.Logging.EventSource": "(,10.0.32767]", + "Microsoft.Extensions.Logging.TraceSource": "(,10.0.32767]", + "Microsoft.Extensions.ObjectPool": "(,10.0.32767]", + "Microsoft.Extensions.Options": "(,10.0.32767]", + "Microsoft.Extensions.Options.ConfigurationExtensions": "(,10.0.32767]", + "Microsoft.Extensions.Options.DataAnnotations": "(,10.0.32767]", + "Microsoft.Extensions.Primitives": "(,10.0.32767]", + "Microsoft.Extensions.Validation": "(,10.0.32767]", + "Microsoft.Extensions.WebEncoders": "(,10.0.32767]", + "Microsoft.JSInterop": "(,10.0.32767]", + "Microsoft.Net.Http.Headers": "(,10.0.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.EventLog": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Cbor": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Cryptography.Xml": "(,10.0.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.RateLimiting": "(,10.0.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj", + "projectName": "e-suite.Utilities.Pagination", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "dependencies": { + "Microsoft.EntityFrameworkCore": { + "target": "Package", + "version": "[10.0.2, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.g.props b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.g.props new file mode 100644 index 0000000..10ae078 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.g.props @@ -0,0 +1,19 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\me\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages + PackageReference + 7.0.0 + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.g.targets b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.g.targets new file mode 100644 index 0000000..c6fc552 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/e-suite.Modules.PerformanceManager.csproj.nuget.g.targets @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/project.assets.json b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/project.assets.json new file mode 100644 index 0000000..f8bdac8 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/project.assets.json @@ -0,0 +1,1335 @@ +{ + "version": 3, + "targets": { + "net10.0": { + "Autofac/9.0.0": { + "type": "package", + "compile": { + "lib/net10.0/Autofac.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Autofac.dll": { + "related": ".xml" + } + } + }, + "Microsoft.EntityFrameworkCore/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "10.0.2", + "Microsoft.EntityFrameworkCore.Analyzers": "10.0.2", + "Microsoft.Extensions.Caching.Memory": "10.0.2", + "Microsoft.Extensions.Logging": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.EntityFrameworkCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.EntityFrameworkCore.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props": {} + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/10.0.2": { + "type": "package", + "compile": { + "lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/10.0.2": { + "type": "package" + }, + "Microsoft.Extensions.Caching.Abstractions/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.Caching.Memory/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "10.0.2", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.2", + "Microsoft.Extensions.Logging.Abstractions": "10.0.2", + "Microsoft.Extensions.Options": "10.0.2", + "Microsoft.Extensions.Primitives": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.2", + "Microsoft.Extensions.Primitives": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Configuration.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Configuration.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Abstractions/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Binder/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.2", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Configuration.Binder.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Configuration.Binder.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netstandard2.0/Microsoft.Extensions.Configuration.Binder.targets": {} + } + }, + "Microsoft.Extensions.DependencyInjection/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/10.0.2": { + "type": "package", + "compile": { + "lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.Logging/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "10.0.2", + "Microsoft.Extensions.Logging.Abstractions": "10.0.2", + "Microsoft.Extensions.Options": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/Microsoft.Extensions.Logging.Abstractions.targets": {} + } + }, + "Microsoft.Extensions.Options/10.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.2", + "Microsoft.Extensions.Primitives": "10.0.2" + }, + "compile": { + "lib/net10.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/Microsoft.Extensions.Options.targets": {} + } + }, + "Microsoft.Extensions.Primitives/10.0.2": { + "type": "package", + "compile": { + "lib/net10.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net10.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "Newtonsoft.Json/13.0.4": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "System.Linq.Dynamic.Core/1.7.1": { + "type": "package", + "compile": { + "lib/net10.0/System.Linq.Dynamic.Core.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net10.0/System.Linq.Dynamic.Core.dll": { + "related": ".pdb;.xml" + } + } + }, + "e-suite.API.Common/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v10.0", + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "10.0.2", + "e-suite.Database.Core": "1.0.0", + "e-suite.Utilities.Pagination": "1.0.0" + }, + "compile": { + "bin/placeholder/e-suite.API.Common.dll": {} + }, + "runtime": { + "bin/placeholder/e-suite.API.Common.dll": {} + } + }, + "e-suite.Database.Audit/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v10.0", + "dependencies": { + "Microsoft.EntityFrameworkCore": "10.0.2", + "Newtonsoft.Json": "13.0.4", + "System.Linq.Dynamic.Core": "1.7.1", + "eSuite.Core": "1.0.0" + }, + "compile": { + "bin/placeholder/e-suite.Database.Audit.dll": {} + }, + "runtime": { + "bin/placeholder/e-suite.Database.Audit.dll": {} + } + }, + "e-suite.Database.Core/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v10.0", + "dependencies": { + "e-suite.Database.Audit": "1.0.0", + "eSuite.Core": "1.0.0", + "e_suite.Nuget.PasswordHasher": "1.0.0" + }, + "compile": { + "bin/placeholder/e-suite.Database.Core.dll": {} + }, + "runtime": { + "bin/placeholder/e-suite.Database.Core.dll": {} + } + }, + "e-suite.Utilities.Pagination/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v10.0", + "dependencies": { + "Microsoft.EntityFrameworkCore": "10.0.2" + }, + "compile": { + "bin/placeholder/e-suite.Utilities.Pagination.dll": {} + }, + "runtime": { + "bin/placeholder/e-suite.Utilities.Pagination.dll": {} + } + }, + "eSuite.Core/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v10.0", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.2", + "Microsoft.Extensions.Configuration.Binder": "10.0.2" + }, + "compile": { + "bin/placeholder/eSuite.Core.dll": {} + }, + "runtime": { + "bin/placeholder/eSuite.Core.dll": {} + } + }, + "e_suite.Nuget.PasswordHasher/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v10.0", + "compile": { + "bin/placeholder/e_suite.Nuget.PasswordHasher.dll": {} + }, + "runtime": { + "bin/placeholder/e_suite.Nuget.PasswordHasher.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + } + } + }, + "libraries": { + "Autofac/9.0.0": { + "sha512": "G8TpUMVIq1pEAMuAao8h5MKduY91SotjgK93wQb5LaxbJUVE0/XjCA6t2SOp+AkPC3GB/C2MAiF2D7krYjraFw==", + "type": "package", + "path": "autofac/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "autofac.9.0.0.nupkg.sha512", + "autofac.nuspec", + "icon.png", + "lib/net10.0/Autofac.dll", + "lib/net10.0/Autofac.xml", + "lib/net8.0/Autofac.dll", + "lib/net8.0/Autofac.xml", + "lib/netstandard2.0/Autofac.dll", + "lib/netstandard2.0/Autofac.xml", + "lib/netstandard2.1/Autofac.dll", + "lib/netstandard2.1/Autofac.xml" + ] + }, + "Microsoft.EntityFrameworkCore/10.0.2": { + "sha512": "d3+XKbLSHPCu3vwpXECoXcFbvGKmAhEeUmc1xy2czmuPnEF7rZN2HP5ZGMwCMbAKk4B01+nS4HixSMo2Vf/Y9g==", + "type": "package", + "path": "microsoft.entityframeworkcore/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props", + "lib/net10.0/Microsoft.EntityFrameworkCore.dll", + "lib/net10.0/Microsoft.EntityFrameworkCore.xml", + "microsoft.entityframeworkcore.10.0.2.nupkg.sha512", + "microsoft.entityframeworkcore.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore.Abstractions/10.0.2": { + "sha512": "BzAwIU5mYeOmnKbEXrkwx7feW2V+zUTrK/kRonSib94tjvc0/iRj2a4N6YGXRhTNjaFP3tvCMIDaX1vIFF6dkg==", + "type": "package", + "path": "microsoft.entityframeworkcore.abstractions/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll", + "lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.xml", + "microsoft.entityframeworkcore.abstractions.10.0.2.nupkg.sha512", + "microsoft.entityframeworkcore.abstractions.nuspec" + ] + }, + "Microsoft.EntityFrameworkCore.Analyzers/10.0.2": { + "sha512": "5C8aKN2HFhXfLhkrVvQ6yH990nw35pS7HNnwdBc628zIREaKJ4/rkdCXzxOdZo/SnCT3Kg7a/CqnhlzuJhlD4Q==", + "type": "package", + "path": "microsoft.entityframeworkcore.analyzers/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "analyzers/dotnet/cs/Microsoft.EntityFrameworkCore.Analyzers.dll", + "docs/PACKAGE.md", + "microsoft.entityframeworkcore.analyzers.10.0.2.nupkg.sha512", + "microsoft.entityframeworkcore.analyzers.nuspec" + ] + }, + "Microsoft.Extensions.Caching.Abstractions/10.0.2": { + "sha512": "WIRPDa/qoKHmJhTAPCO/zLu9kRLQ2Fd6HD5tzgdXJ3xGEVXDHP6FvakKJjynwKrVDld8H4G4tcbW53wuC/wxMQ==", + "type": "package", + "path": "microsoft.extensions.caching.abstractions/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Abstractions.targets", + "lib/net10.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net10.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net9.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net9.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.xml", + "microsoft.extensions.caching.abstractions.10.0.2.nupkg.sha512", + "microsoft.extensions.caching.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Caching.Memory/10.0.2": { + "sha512": "MkdPYdtsu0Ta4m9Di4XnWVdO9u+wi1LtvisoR1EteIxsXWO/+3iyAPH6RZbw2lBlWZu9lastbl2YsHVIaL9j+g==", + "type": "package", + "path": "microsoft.extensions.caching.memory/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Memory.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Memory.targets", + "lib/net10.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net10.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/net462/Microsoft.Extensions.Caching.Memory.dll", + "lib/net462/Microsoft.Extensions.Caching.Memory.xml", + "lib/net8.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net8.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/net9.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net9.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.xml", + "microsoft.extensions.caching.memory.10.0.2.nupkg.sha512", + "microsoft.extensions.caching.memory.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration/10.0.2": { + "sha512": "Lws+o4DFw6p5NquRoYA3d5QVvi49ugNw7TxbW4QGLsL8F1LCCyJqWFy0+RMQ/hzUuS9aKV5NJ/XGAF5N9/RQcQ==", + "type": "package", + "path": "microsoft.extensions.configuration/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.targets", + "lib/net10.0/Microsoft.Extensions.Configuration.dll", + "lib/net10.0/Microsoft.Extensions.Configuration.xml", + "lib/net462/Microsoft.Extensions.Configuration.dll", + "lib/net462/Microsoft.Extensions.Configuration.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.xml", + "lib/net9.0/Microsoft.Extensions.Configuration.dll", + "lib/net9.0/Microsoft.Extensions.Configuration.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.xml", + "microsoft.extensions.configuration.10.0.2.nupkg.sha512", + "microsoft.extensions.configuration.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Abstractions/10.0.2": { + "sha512": "KC5PslaTDnTuTvyke0KYAVBYdZ7IVTsU3JhHe69BpEbHLcj1YThP3bIGtZNOkZfast2AuLnul5lk4rZKxAdUGQ==", + "type": "package", + "path": "microsoft.extensions.configuration.abstractions/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.Abstractions.targets", + "lib/net10.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net10.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net462/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net9.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net9.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "microsoft.extensions.configuration.abstractions.10.0.2.nupkg.sha512", + "microsoft.extensions.configuration.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Binder/10.0.2": { + "sha512": "/SdW50prUuenglSy7MXU3eVQkOk4/J4fjc+GIhv4NkTmaZOQyTqpVAYi8nRjNtOKHzCy7g5cSlOSgkbT7clLwQ==", + "type": "package", + "path": "microsoft.extensions.configuration.binder/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/cs/Microsoft.Extensions.Configuration.Binder.SourceGeneration.dll", + "analyzers/dotnet/cs/cs/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/de/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/es/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/fr/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/it/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/ja/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/ko/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/pl/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/pt-BR/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/ru/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/tr/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/zh-Hans/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/zh-Hant/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Configuration.Binder.targets", + "lib/net10.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net10.0/Microsoft.Extensions.Configuration.Binder.xml", + "lib/net462/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net462/Microsoft.Extensions.Configuration.Binder.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.Binder.xml", + "lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net9.0/Microsoft.Extensions.Configuration.Binder.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Binder.xml", + "microsoft.extensions.configuration.binder.10.0.2.nupkg.sha512", + "microsoft.extensions.configuration.binder.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection/10.0.2": { + "sha512": "J/Zmp6fY93JbaiZ11ckWvcyxMPjD6XVwIHQXBjryTBgn7O6O20HYg9uVLFcZlNfgH78MnreE/7EH+hjfzn7VyA==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.targets", + "lib/net10.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net10.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/net462/Microsoft.Extensions.DependencyInjection.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.xml", + "lib/net8.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net8.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/net9.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net9.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.xml", + "microsoft.extensions.dependencyinjection.10.0.2.nupkg.sha512", + "microsoft.extensions.dependencyinjection.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/10.0.2": { + "sha512": "zOIurr59+kUf9vNcsUkCvKWZv+fPosUZXURZesYkJCvl0EzTc9F7maAO4Cd2WEV7ZJJ0AZrFQvuH6Npph9wdBw==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection.abstractions/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "microsoft.extensions.dependencyinjection.abstractions.10.0.2.nupkg.sha512", + "microsoft.extensions.dependencyinjection.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Logging/10.0.2": { + "sha512": "a0EWuBs6D3d7XMGroDXm+WsAi5CVVfjOJvyxurzWnuhBN9CO+1qHKcrKV1JK7H/T4ZtHIoVCOX/YyWM8K87qtw==", + "type": "package", + "path": "microsoft.extensions.logging/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Logging.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.targets", + "lib/net10.0/Microsoft.Extensions.Logging.dll", + "lib/net10.0/Microsoft.Extensions.Logging.xml", + "lib/net462/Microsoft.Extensions.Logging.dll", + "lib/net462/Microsoft.Extensions.Logging.xml", + "lib/net8.0/Microsoft.Extensions.Logging.dll", + "lib/net8.0/Microsoft.Extensions.Logging.xml", + "lib/net9.0/Microsoft.Extensions.Logging.dll", + "lib/net9.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.1/Microsoft.Extensions.Logging.xml", + "microsoft.extensions.logging.10.0.2.nupkg.sha512", + "microsoft.extensions.logging.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/10.0.2": { + "sha512": "RZkez/JjpnO+MZ6efKkSynN6ZztLpw3WbxNzjLCPBd97wWj1S9ZYPWi0nmT4kWBRa6atHsdM1ydGkUr8GudyDQ==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net8.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "lib/net10.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net10.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net9.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net9.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.10.0.2.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Options/10.0.2": { + "sha512": "1De2LJjmxdqopI5AYC5dIhoZQ79AR5ayywxNF1rXrXFtKQfbQOV9+n/IsZBa7qWlr0MqoGpW8+OY2v/57udZOA==", + "type": "package", + "path": "microsoft.extensions.options/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Options.SourceGeneration.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "buildTransitive/net461/Microsoft.Extensions.Options.targets", + "buildTransitive/net462/Microsoft.Extensions.Options.targets", + "buildTransitive/net8.0/Microsoft.Extensions.Options.targets", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Options.targets", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Options.targets", + "lib/net10.0/Microsoft.Extensions.Options.dll", + "lib/net10.0/Microsoft.Extensions.Options.xml", + "lib/net462/Microsoft.Extensions.Options.dll", + "lib/net462/Microsoft.Extensions.Options.xml", + "lib/net8.0/Microsoft.Extensions.Options.dll", + "lib/net8.0/Microsoft.Extensions.Options.xml", + "lib/net9.0/Microsoft.Extensions.Options.dll", + "lib/net9.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.0/Microsoft.Extensions.Options.dll", + "lib/netstandard2.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.1/Microsoft.Extensions.Options.dll", + "lib/netstandard2.1/Microsoft.Extensions.Options.xml", + "microsoft.extensions.options.10.0.2.nupkg.sha512", + "microsoft.extensions.options.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Primitives/10.0.2": { + "sha512": "QmSiO+oLBEooGgB3i0GRXyeYRDHjllqt3k365jwfZlYWhvSHA3UL2NEVV5m8aZa041eIlblo6KMI5txvTMpTwA==", + "type": "package", + "path": "microsoft.extensions.primitives/10.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Primitives.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Primitives.targets", + "lib/net10.0/Microsoft.Extensions.Primitives.dll", + "lib/net10.0/Microsoft.Extensions.Primitives.xml", + "lib/net462/Microsoft.Extensions.Primitives.dll", + "lib/net462/Microsoft.Extensions.Primitives.xml", + "lib/net8.0/Microsoft.Extensions.Primitives.dll", + "lib/net8.0/Microsoft.Extensions.Primitives.xml", + "lib/net9.0/Microsoft.Extensions.Primitives.dll", + "lib/net9.0/Microsoft.Extensions.Primitives.xml", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.dll", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.xml", + "microsoft.extensions.primitives.10.0.2.nupkg.sha512", + "microsoft.extensions.primitives.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Newtonsoft.Json/13.0.4": { + "sha512": "pdgNNMai3zv51W5aq268sujXUyx7SNdE2bj1wZcWjAQrKMFZV260lbqYop1d2GM67JI1huLRwxo9ZqnfF/lC6A==", + "type": "package", + "path": "newtonsoft.json/13.0.4", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.4.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "System.Linq.Dynamic.Core/1.7.1": { + "sha512": "qlgku/j9r0fei52yxR5ho9nC/fWGZuaELqPkZmJm24QZbBW4cL3sVWri1dZ0cKgARD7cgFKBdRqzxYoIG5Q0Cg==", + "type": "package", + "path": "system.linq.dynamic.core/1.7.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "PackageReadme.md", + "lib/net10.0/System.Linq.Dynamic.Core.dll", + "lib/net10.0/System.Linq.Dynamic.Core.pdb", + "lib/net10.0/System.Linq.Dynamic.Core.xml", + "lib/net35/System.Linq.Dynamic.Core.dll", + "lib/net35/System.Linq.Dynamic.Core.pdb", + "lib/net35/System.Linq.Dynamic.Core.xml", + "lib/net40/System.Linq.Dynamic.Core.dll", + "lib/net40/System.Linq.Dynamic.Core.pdb", + "lib/net40/System.Linq.Dynamic.Core.xml", + "lib/net45/System.Linq.Dynamic.Core.dll", + "lib/net45/System.Linq.Dynamic.Core.pdb", + "lib/net45/System.Linq.Dynamic.Core.xml", + "lib/net452/System.Linq.Dynamic.Core.dll", + "lib/net452/System.Linq.Dynamic.Core.pdb", + "lib/net452/System.Linq.Dynamic.Core.xml", + "lib/net46/System.Linq.Dynamic.Core.dll", + "lib/net46/System.Linq.Dynamic.Core.pdb", + "lib/net46/System.Linq.Dynamic.Core.xml", + "lib/net5.0/System.Linq.Dynamic.Core.dll", + "lib/net5.0/System.Linq.Dynamic.Core.pdb", + "lib/net5.0/System.Linq.Dynamic.Core.xml", + "lib/net6.0/System.Linq.Dynamic.Core.dll", + "lib/net6.0/System.Linq.Dynamic.Core.pdb", + "lib/net6.0/System.Linq.Dynamic.Core.xml", + "lib/net7.0/System.Linq.Dynamic.Core.dll", + "lib/net7.0/System.Linq.Dynamic.Core.pdb", + "lib/net7.0/System.Linq.Dynamic.Core.xml", + "lib/net8.0/System.Linq.Dynamic.Core.dll", + "lib/net8.0/System.Linq.Dynamic.Core.pdb", + "lib/net8.0/System.Linq.Dynamic.Core.xml", + "lib/net9.0/System.Linq.Dynamic.Core.dll", + "lib/net9.0/System.Linq.Dynamic.Core.pdb", + "lib/net9.0/System.Linq.Dynamic.Core.xml", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.dll", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.pdb", + "lib/netcoreapp2.1/System.Linq.Dynamic.Core.xml", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.dll", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.pdb", + "lib/netcoreapp3.1/System.Linq.Dynamic.Core.xml", + "lib/netstandard1.3/System.Linq.Dynamic.Core.dll", + "lib/netstandard1.3/System.Linq.Dynamic.Core.pdb", + "lib/netstandard1.3/System.Linq.Dynamic.Core.xml", + "lib/netstandard2.0/System.Linq.Dynamic.Core.dll", + "lib/netstandard2.0/System.Linq.Dynamic.Core.pdb", + "lib/netstandard2.0/System.Linq.Dynamic.Core.xml", + "lib/netstandard2.1/System.Linq.Dynamic.Core.dll", + "lib/netstandard2.1/System.Linq.Dynamic.Core.pdb", + "lib/netstandard2.1/System.Linq.Dynamic.Core.xml", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.dll", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.pdb", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.pri", + "lib/uap10.0.10240/System.Linq.Dynamic.Core.xml", + "logo.png", + "system.linq.dynamic.core.1.7.1.nupkg.sha512", + "system.linq.dynamic.core.nuspec" + ] + }, + "e-suite.API.Common/1.0.0": { + "type": "project", + "path": "../../e-suite.API.Common/e-suite.API.Common/e-suite.API.Common.csproj", + "msbuildProject": "../../e-suite.API.Common/e-suite.API.Common/e-suite.API.Common.csproj" + }, + "e-suite.Database.Audit/1.0.0": { + "type": "project", + "path": "../../e-suite.Database.Audit/e-suite.Database.Audit/e-suite.Database.Audit.csproj", + "msbuildProject": "../../e-suite.Database.Audit/e-suite.Database.Audit/e-suite.Database.Audit.csproj" + }, + "e-suite.Database.Core/1.0.0": { + "type": "project", + "path": "../../e-suite.Database.Core/e-suite.Database.Core/e-suite.Database.Core.csproj", + "msbuildProject": "../../e-suite.Database.Core/e-suite.Database.Core/e-suite.Database.Core.csproj" + }, + "e-suite.Utilities.Pagination/1.0.0": { + "type": "project", + "path": "../../e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.csproj", + "msbuildProject": "../../e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.csproj" + }, + "eSuite.Core/1.0.0": { + "type": "project", + "path": "../../e-suite.Core/eSuite.Core/eSuite.Core.csproj", + "msbuildProject": "../../e-suite.Core/eSuite.Core/eSuite.Core.csproj" + }, + "e_suite.Nuget.PasswordHasher/1.0.0": { + "type": "project", + "path": "../../e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.csproj", + "msbuildProject": "../../e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.csproj" + } + }, + "projectFileDependencyGroups": { + "net10.0": [ + "Autofac >= 9.0.0", + "e-suite.API.Common >= 1.0.0", + "e-suite.Utilities.Pagination >= 1.0.0" + ] + }, + "packageFolders": { + "C:\\Users\\me\\.nuget\\packages\\": {}, + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj", + "projectName": "e-suite.Modules.PerformanceManager", + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj", + "packagesPath": "C:\\Users\\me\\.nuget\\packages\\", + "outputPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\NuGet.Config", + "C:\\Users\\me\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net10.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {}, + "https://sunbranding.pkgs.visualstudio.com/e-suite/_packaging/e-suite/nuget/v3/index.json": {} + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "projectReferences": { + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.API.Common\\e-suite.API.Common\\e-suite.API.Common.csproj" + }, + "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj": { + "projectPath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination\\e-suite.Utilities.Pagination.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "net10.0": { + "targetAlias": "net10.0", + "dependencies": { + "Autofac": { + "target": "Package", + "version": "[9.0.0, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json", + "packagesToPrune": { + "Microsoft.CSharp": "(,4.7.32767]", + "Microsoft.VisualBasic": "(,10.4.32767]", + "Microsoft.Win32.Primitives": "(,4.3.32767]", + "Microsoft.Win32.Registry": "(,5.0.32767]", + "runtime.any.System.Collections": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.any.System.Globalization": "(,4.3.32767]", + "runtime.any.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.any.System.IO": "(,4.3.32767]", + "runtime.any.System.Reflection": "(,4.3.32767]", + "runtime.any.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.any.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.any.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.any.System.Runtime": "(,4.3.32767]", + "runtime.any.System.Runtime.Handles": "(,4.3.32767]", + "runtime.any.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.any.System.Text.Encoding": "(,4.3.32767]", + "runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.any.System.Threading.Tasks": "(,4.3.32767]", + "runtime.any.System.Threading.Timer": "(,4.3.32767]", + "runtime.aot.System.Collections": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]", + "runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]", + "runtime.aot.System.Globalization": "(,4.3.32767]", + "runtime.aot.System.Globalization.Calendars": "(,4.3.32767]", + "runtime.aot.System.IO": "(,4.3.32767]", + "runtime.aot.System.Reflection": "(,4.3.32767]", + "runtime.aot.System.Reflection.Extensions": "(,4.3.32767]", + "runtime.aot.System.Reflection.Primitives": "(,4.3.32767]", + "runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]", + "runtime.aot.System.Runtime": "(,4.3.32767]", + "runtime.aot.System.Runtime.Handles": "(,4.3.32767]", + "runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding": "(,4.3.32767]", + "runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]", + "runtime.aot.System.Threading.Tasks": "(,4.3.32767]", + "runtime.aot.System.Threading.Timer": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]", + "runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]", + "runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.unix.System.Console": "(,4.3.32767]", + "runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.unix.System.IO.FileSystem": "(,4.3.32767]", + "runtime.unix.System.Net.Primitives": "(,4.3.32767]", + "runtime.unix.System.Net.Sockets": "(,4.3.32767]", + "runtime.unix.System.Private.Uri": "(,4.3.32767]", + "runtime.unix.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]", + "runtime.win.System.Console": "(,4.3.32767]", + "runtime.win.System.Diagnostics.Debug": "(,4.3.32767]", + "runtime.win.System.IO.FileSystem": "(,4.3.32767]", + "runtime.win.System.Net.Primitives": "(,4.3.32767]", + "runtime.win.System.Net.Sockets": "(,4.3.32767]", + "runtime.win.System.Runtime.Extensions": "(,4.3.32767]", + "runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]", + "runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]", + "runtime.win7.System.Private.Uri": "(,4.3.32767]", + "runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]", + "System.AppContext": "(,4.3.32767]", + "System.Buffers": "(,5.0.32767]", + "System.Collections": "(,4.3.32767]", + "System.Collections.Concurrent": "(,4.3.32767]", + "System.Collections.Immutable": "(,10.0.32767]", + "System.Collections.NonGeneric": "(,4.3.32767]", + "System.Collections.Specialized": "(,4.3.32767]", + "System.ComponentModel": "(,4.3.32767]", + "System.ComponentModel.Annotations": "(,4.3.32767]", + "System.ComponentModel.EventBasedAsync": "(,4.3.32767]", + "System.ComponentModel.Primitives": "(,4.3.32767]", + "System.ComponentModel.TypeConverter": "(,4.3.32767]", + "System.Console": "(,4.3.32767]", + "System.Data.Common": "(,4.3.32767]", + "System.Data.DataSetExtensions": "(,4.4.32767]", + "System.Diagnostics.Contracts": "(,4.3.32767]", + "System.Diagnostics.Debug": "(,4.3.32767]", + "System.Diagnostics.DiagnosticSource": "(,10.0.32767]", + "System.Diagnostics.FileVersionInfo": "(,4.3.32767]", + "System.Diagnostics.Process": "(,4.3.32767]", + "System.Diagnostics.StackTrace": "(,4.3.32767]", + "System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]", + "System.Diagnostics.Tools": "(,4.3.32767]", + "System.Diagnostics.TraceSource": "(,4.3.32767]", + "System.Diagnostics.Tracing": "(,4.3.32767]", + "System.Drawing.Primitives": "(,4.3.32767]", + "System.Dynamic.Runtime": "(,4.3.32767]", + "System.Formats.Asn1": "(,10.0.32767]", + "System.Formats.Tar": "(,10.0.32767]", + "System.Globalization": "(,4.3.32767]", + "System.Globalization.Calendars": "(,4.3.32767]", + "System.Globalization.Extensions": "(,4.3.32767]", + "System.IO": "(,4.3.32767]", + "System.IO.Compression": "(,4.3.32767]", + "System.IO.Compression.ZipFile": "(,4.3.32767]", + "System.IO.FileSystem": "(,4.3.32767]", + "System.IO.FileSystem.AccessControl": "(,4.4.32767]", + "System.IO.FileSystem.DriveInfo": "(,4.3.32767]", + "System.IO.FileSystem.Primitives": "(,4.3.32767]", + "System.IO.FileSystem.Watcher": "(,4.3.32767]", + "System.IO.IsolatedStorage": "(,4.3.32767]", + "System.IO.MemoryMappedFiles": "(,4.3.32767]", + "System.IO.Pipelines": "(,10.0.32767]", + "System.IO.Pipes": "(,4.3.32767]", + "System.IO.Pipes.AccessControl": "(,5.0.32767]", + "System.IO.UnmanagedMemoryStream": "(,4.3.32767]", + "System.Linq": "(,4.3.32767]", + "System.Linq.AsyncEnumerable": "(,10.0.32767]", + "System.Linq.Expressions": "(,4.3.32767]", + "System.Linq.Parallel": "(,4.3.32767]", + "System.Linq.Queryable": "(,4.3.32767]", + "System.Memory": "(,5.0.32767]", + "System.Net.Http": "(,4.3.32767]", + "System.Net.Http.Json": "(,10.0.32767]", + "System.Net.NameResolution": "(,4.3.32767]", + "System.Net.NetworkInformation": "(,4.3.32767]", + "System.Net.Ping": "(,4.3.32767]", + "System.Net.Primitives": "(,4.3.32767]", + "System.Net.Requests": "(,4.3.32767]", + "System.Net.Security": "(,4.3.32767]", + "System.Net.ServerSentEvents": "(,10.0.32767]", + "System.Net.Sockets": "(,4.3.32767]", + "System.Net.WebHeaderCollection": "(,4.3.32767]", + "System.Net.WebSockets": "(,4.3.32767]", + "System.Net.WebSockets.Client": "(,4.3.32767]", + "System.Numerics.Vectors": "(,5.0.32767]", + "System.ObjectModel": "(,4.3.32767]", + "System.Private.DataContractSerialization": "(,4.3.32767]", + "System.Private.Uri": "(,4.3.32767]", + "System.Reflection": "(,4.3.32767]", + "System.Reflection.DispatchProxy": "(,6.0.32767]", + "System.Reflection.Emit": "(,4.7.32767]", + "System.Reflection.Emit.ILGeneration": "(,4.7.32767]", + "System.Reflection.Emit.Lightweight": "(,4.7.32767]", + "System.Reflection.Extensions": "(,4.3.32767]", + "System.Reflection.Metadata": "(,10.0.32767]", + "System.Reflection.Primitives": "(,4.3.32767]", + "System.Reflection.TypeExtensions": "(,4.3.32767]", + "System.Resources.Reader": "(,4.3.32767]", + "System.Resources.ResourceManager": "(,4.3.32767]", + "System.Resources.Writer": "(,4.3.32767]", + "System.Runtime": "(,4.3.32767]", + "System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]", + "System.Runtime.CompilerServices.VisualC": "(,4.3.32767]", + "System.Runtime.Extensions": "(,4.3.32767]", + "System.Runtime.Handles": "(,4.3.32767]", + "System.Runtime.InteropServices": "(,4.3.32767]", + "System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]", + "System.Runtime.Loader": "(,4.3.32767]", + "System.Runtime.Numerics": "(,4.3.32767]", + "System.Runtime.Serialization.Formatters": "(,4.3.32767]", + "System.Runtime.Serialization.Json": "(,4.3.32767]", + "System.Runtime.Serialization.Primitives": "(,4.3.32767]", + "System.Runtime.Serialization.Xml": "(,4.3.32767]", + "System.Security.AccessControl": "(,6.0.32767]", + "System.Security.Claims": "(,4.3.32767]", + "System.Security.Cryptography.Algorithms": "(,4.3.32767]", + "System.Security.Cryptography.Cng": "(,5.0.32767]", + "System.Security.Cryptography.Csp": "(,4.3.32767]", + "System.Security.Cryptography.Encoding": "(,4.3.32767]", + "System.Security.Cryptography.OpenSsl": "(,5.0.32767]", + "System.Security.Cryptography.Primitives": "(,4.3.32767]", + "System.Security.Cryptography.X509Certificates": "(,4.3.32767]", + "System.Security.Principal": "(,4.3.32767]", + "System.Security.Principal.Windows": "(,5.0.32767]", + "System.Security.SecureString": "(,4.3.32767]", + "System.Text.Encoding": "(,4.3.32767]", + "System.Text.Encoding.CodePages": "(,10.0.32767]", + "System.Text.Encoding.Extensions": "(,4.3.32767]", + "System.Text.Encodings.Web": "(,10.0.32767]", + "System.Text.Json": "(,10.0.32767]", + "System.Text.RegularExpressions": "(,4.3.32767]", + "System.Threading": "(,4.3.32767]", + "System.Threading.AccessControl": "(,10.0.32767]", + "System.Threading.Channels": "(,10.0.32767]", + "System.Threading.Overlapped": "(,4.3.32767]", + "System.Threading.Tasks": "(,4.3.32767]", + "System.Threading.Tasks.Dataflow": "(,10.0.32767]", + "System.Threading.Tasks.Extensions": "(,5.0.32767]", + "System.Threading.Tasks.Parallel": "(,4.3.32767]", + "System.Threading.Thread": "(,4.3.32767]", + "System.Threading.ThreadPool": "(,4.3.32767]", + "System.Threading.Timer": "(,4.3.32767]", + "System.ValueTuple": "(,4.5.32767]", + "System.Xml.ReaderWriter": "(,4.3.32767]", + "System.Xml.XDocument": "(,4.3.32767]", + "System.Xml.XmlDocument": "(,4.3.32767]", + "System.Xml.XmlSerializer": "(,4.3.32767]", + "System.Xml.XPath": "(,4.3.32767]", + "System.Xml.XPath.XDocument": "(,5.0.32767]" + } + } + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/project.nuget.cache b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/project.nuget.cache new file mode 100644 index 0000000..359d101 --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/obj/project.nuget.cache @@ -0,0 +1,26 @@ +{ + "version": 2, + "dgSpecHash": "lr0GWqPTw4M=", + "success": true, + "projectFilePath": "C:\\Users\\me\\OneDrive\\Code\\Sun\\e-suite\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager\\e-suite.Modules.PerformanceManager.csproj", + "expectedPackageFiles": [ + "C:\\Users\\me\\.nuget\\packages\\autofac\\9.0.0\\autofac.9.0.0.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore\\10.0.2\\microsoft.entityframeworkcore.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore.abstractions\\10.0.2\\microsoft.entityframeworkcore.abstractions.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.entityframeworkcore.analyzers\\10.0.2\\microsoft.entityframeworkcore.analyzers.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\10.0.2\\microsoft.extensions.caching.abstractions.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.caching.memory\\10.0.2\\microsoft.extensions.caching.memory.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.configuration\\10.0.2\\microsoft.extensions.configuration.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\10.0.2\\microsoft.extensions.configuration.abstractions.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.configuration.binder\\10.0.2\\microsoft.extensions.configuration.binder.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\10.0.2\\microsoft.extensions.dependencyinjection.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\10.0.2\\microsoft.extensions.dependencyinjection.abstractions.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.logging\\10.0.2\\microsoft.extensions.logging.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\10.0.2\\microsoft.extensions.logging.abstractions.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.options\\10.0.2\\microsoft.extensions.options.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\microsoft.extensions.primitives\\10.0.2\\microsoft.extensions.primitives.10.0.2.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\newtonsoft.json\\13.0.4\\newtonsoft.json.13.0.4.nupkg.sha512", + "C:\\Users\\me\\.nuget\\packages\\system.linq.dynamic.core\\1.7.1\\system.linq.dynamic.core.1.7.1.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/repository/PerformanceManagerRepository.cs b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/repository/PerformanceManagerRepository.cs new file mode 100644 index 0000000..a89215b --- /dev/null +++ b/e-suite.Modules.PerformanceManager/e-suite.Modules.PerformanceManager/repository/PerformanceManagerRepository.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Diagnostics; +using eSuite.Core.Clock; + +namespace e_suite.Modules.DiagnosticManager.repository; + +public class PerformanceManagerRepository: RepositoryBase, IPerformanceManagerRepository +{ + private readonly IClock _clock; + + public PerformanceManagerRepository(IEsuiteDatabaseDbContext databaseDbContext, IClock clock) : base(databaseDbContext) + { + _clock = clock; + } + + public IQueryable GetPerformanceReportSummary() + { + var now = _clock.GetNow; + + return DatabaseDbContext.PerformanceReports + .Where( x => x.StartDateTime > now.AddYears(-1)) + .GroupBy( x => new{ x.Host, x.ControllerName, x.ActionName, x.RequestType} ) + .Select(r => new PerformanceReportSummary + { + Host = r.Key.Host, + ControllerName = r.Key.ControllerName, + ActionName = r.Key.ActionName, + RequestType = r.Key.RequestType, + MinTotalTimeMs = r.ToArray().Min( x => x.TotalTimeMS), + MaxTotalTimeMS = r.ToArray().Max(x => x.TotalTimeMS), + AvgTotalTimeMs = r.ToArray().Average(x => x.TotalTimeMS), + SumTotalTimeMs = r.ToArray().Sum(x => x.TotalTimeMS), + Count = r.Count() + }); + } + + public IQueryable GetPerformanceReports(string hostName, string controllerName, string actionName, string requestType) + { + return DatabaseDbContext.PerformanceReports + .Where( x => x.Host == hostName && x.ControllerName == controllerName && x.ActionName == actionName && x.RequestType == requestType); + } +} diff --git a/e-suite.Modules.RoleManager/.gitattributes b/e-suite.Modules.RoleManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.RoleManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.RoleManager/.gitignore b/e-suite.Modules.RoleManager/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Modules.RoleManager/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/.runsettings b/e-suite.Modules.RoleManager/.runsettings new file mode 100644 index 0000000..a43367b --- /dev/null +++ b/e-suite.Modules.RoleManager/.runsettings @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + .*microsoft.testplatform.* + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/README.md b/e-suite.Modules.RoleManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.RoleManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/azure-pipelines.yml b/e-suite.Modules.RoleManager/azure-pipelines.yml new file mode 100644 index 0000000..9e97f33 --- /dev/null +++ b/e-suite.Modules.RoleManager/azure-pipelines.yml @@ -0,0 +1,135 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '70' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/AddRoleSecurityAccessUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/AddRoleSecurityAccessUnitTests.cs new file mode 100644 index 0000000..0f57d1e --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/AddRoleSecurityAccessUnitTests.cs @@ -0,0 +1,84 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class AddRoleSecurityAccessUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void AddRoleSecurityAccess_WhenRoleNotFound_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails() + { + UserId = 09127334, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var accessToAdd = new AddRoleSecurityAccess + { + RoleId = new GeneralIdRef() + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.AddRoleSecurityAccess(auditUserDetails, accessToAdd, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Role Not Found")); + } + + [Test] + public async Task AddRoleSecurityAccess_WhenRoleFound_AddsAccessKeysToRole() + { + //Arrange + var auditUserDetails = new AuditUserDetails() + { + UserId = 09127334, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var role = new Role + { + Guid = new Guid("32301f97-2cec-4633-87f9-f87d3270aea5"), + Id = 2314, + IsAdministrator = false, + IsSuperUser = false + }; + RoleManagerRepository.Roles.Add(role); + + var accessToAdd = new AddRoleSecurityAccess + { + RoleId = new GeneralIdRef + { + Guid = role.Guid + }, + SecurityAccess = new List + { + SecurityAccess.AddUser, SecurityAccess.EditUser + } + }; + + //Act + await RoleManager.AddRoleSecurityAccess(auditUserDetails, accessToAdd, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.RoleAccess.Count, Is.EqualTo(2)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/AddRoleUserUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/AddRoleUserUnitTests.cs new file mode 100644 index 0000000..774cbf3 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/AddRoleUserUnitTests.cs @@ -0,0 +1,131 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class AddRoleUserUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void AddRoleUser_RoleNotFound_ThrowsException() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var userRole = new UserRoleIds + { + UserId = new GeneralIdRef(), + RoleId = new GeneralIdRef() + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.AddRoleUser(auditDetails, userRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Role Not Found")); + } + + [Test] + public void AddRoleUser_RoleFoundButUserNotFound_ThrowsException() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var role = new Role + { + Id = 20, + Guid = new Guid("225cd31e-f448-4d30-b2b7-b64ad4a2066a"), + Name = "Test Role" + }; + RoleManagerRepository.Roles.Add(role); + + var userRole = new UserRoleIds + { + UserId = new GeneralIdRef(), + RoleId = new GeneralIdRef + { + Guid = role.Guid + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.AddRoleUser(auditDetails, userRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("User not Found")); + } + + [Test] + public async Task AddRoleUser_UserAndRoleFound_AddsUserRole() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var role = new Role + { + Id = 20, + Guid = new Guid("225cd31e-f448-4d30-b2b7-b64ad4a2066a"), + Name = "Test Role" + }; + RoleManagerRepository.Roles.Add(role); + + var user = new User + { + Guid = new Guid("d51133e6-886b-4021-879b-cb962f375c55"), + Id = 713, + Email = "User@SomePlace.Com" + }; + UserManagerRepository.Users.Add(user); + + var userRole = new UserRoleIds + { + UserId = new GeneralIdRef + { + Guid = user.Guid + }, + RoleId = new GeneralIdRef + { + Guid = role.Guid + } + }; + + //Act + await RoleManager.AddRoleUser(auditDetails, userRole, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.UserRole, Is.Not.Null); + Assert.That(RoleManagerRepository.UserRole!.User, Is.EqualTo(user)); + Assert.That(RoleManagerRepository.UserRole!.Role, Is.EqualTo(role)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/CheckHasDomainAccess.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/CheckHasDomainAccess.cs new file mode 100644 index 0000000..6c2ea64 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/CheckHasDomainAccess.cs @@ -0,0 +1,229 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class CheckHasDomainAccess : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CheckHasDomainAccess_DomainSuppliedButNotFound_ThrowsNotFoundException() + { + //Arrange + var domainToCheck = new GeneralIdRef + { + Guid = new Guid("adfc267b-6dce-4f93-b1e1-33a15861107c") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CheckHasDomainAccess(123, domainToCheck, SecurityAccess.AddUser, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Domain Not Found")); + } + + [Test] + public void CheckHasDomainAccess_DomainNotSuppliedAndNoUserDomainExists_ThrowsNotFoundException() + { + //Arrange + var user = new User + { + Guid = new Guid("52b71abe-5544-4ec1-a3a1-6dfac219a085"), + Id = 234095788, + Domain = new Domain + { + Guid = new Guid("5f4b802c-67dc-4cc6-a34b-c5a9c3388799"), + Id = 2352, + Name = "Does not exist" + } + }; + UserManagerRepository.Users.Add(user); + + GeneralIdRef? domainToCheck = null; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CheckHasDomainAccess(user.Id, domainToCheck, SecurityAccess.AddUser, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Domain Not Found")); + } + + [Test] + public void CheckHasDomainAccess_DomainFound_ThrowsUnauthorizedAccessException() + { + //Arrange + var domain = new Domain + { + Guid = new Guid("097b14d4-d4d4-4142-b0a6-04af95ba6df4"), + Id = 324, + Name = "Existing Domain" + }; + DomainRepository.Domains.Add(domain); + + var domainToCheck = new GeneralIdRef + { + Guid = domain.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CheckHasDomainAccess(123, domainToCheck, SecurityAccess.AddUser, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Attempted to perform an unauthorized operation.")); + } + + [Test] + public void CheckHasDomainAccess_DomainFoundViaUser_ThrowsUnauthorizedAccessException() + { + //Arrange + var domain = new Domain + { + Guid = new Guid("5f4b802c-67dc-4cc6-a34b-c5a9c3388799"), + Id = 2352, + Name = "Does not exist" + }; + DomainRepository.Domains.Add(domain); + + var user = new User + { + Guid = new Guid("52b71abe-5544-4ec1-a3a1-6dfac219a085"), + Id = 234095788, + Domain = domain + }; + UserManagerRepository.Users.Add(user); + + GeneralIdRef? domainToCheck = null; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CheckHasDomainAccess(user.Id, domainToCheck, SecurityAccess.AddUser, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Attempted to perform an unauthorized operation.")); + } + + [Test] + public void CheckHasDomainAccess_UserIsAdmin_DoesNotThrowException() + { + //Arrange + var domain = new Domain + { + Guid = new Guid("5f4b802c-67dc-4cc6-a34b-c5a9c3388799"), + Id = 2352, + Name = "Does not exist" + }; + DomainRepository.Domains.Add(domain); + + var user = new User + { + Guid = new Guid("52b71abe-5544-4ec1-a3a1-6dfac219a085"), + Id = 234095788, + Domain = domain + }; + UserManagerRepository.Users.Add(user); + + var role = new Role + { + Guid = new Guid("875fdb45-4f25-4176-9b74-6aedcc57f746"), + Id = 2342365, + Name = "Administrator", + IsAdministrator = true, + Domain = domain, + DomainId = domain.Id + }; + RoleManagerRepository.Roles.Add(role); + + var userRole = new UserRole + { + User = user, + UserId = user.Id, + Role = role + }; + RoleManagerRepository.RoleUsers.Add(userRole); + + GeneralIdRef? domainToCheck = null; + + //Assert + Assert.DoesNotThrowAsync(async () => + { + //Act + await RoleManager.CheckHasDomainAccess(user.Id, domainToCheck, SecurityAccess.AddUser, CancellationToken.None); + }); + } + + [Test] + public void CheckHasDomainAccess_HasUserAccessViaRoleMemebership_DoesNotThrow() + { + //Arrange + var domain = new Domain + { + Guid = new Guid("5f4b802c-67dc-4cc6-a34b-c5a9c3388799"), + Id = 2352, + Name = "Does not exist" + }; + DomainRepository.Domains.Add(domain); + + var user = new User + { + Guid = new Guid("52b71abe-5544-4ec1-a3a1-6dfac219a085"), + Id = 234095788, + Domain = domain + }; + UserManagerRepository.Users.Add(user); + + var role = new Role + { + Guid = new Guid("875fdb45-4f25-4176-9b74-6aedcc57f746"), + Id = 2342365, + Name = "NotAdmin", + IsAdministrator = false, + Domain = domain, + DomainId = domain.Id + }; + RoleManagerRepository.Roles.Add(role); + + RoleManagerRepository.UserAccess.Add( new UserAccess + { + Domain = domain, + DomainId = domain.Id, + User = user, + UserId = user.Id, + AccessKey = (int)SecurityAccess.AddUser, + }); + + var userRole = new UserRole + { + User = user, + UserId = user.Id, + Role = role + }; + RoleManagerRepository.RoleUsers.Add(userRole); + + GeneralIdRef? domainToCheck = null; + + //Assert + Assert.DoesNotThrowAsync(async () => + { + //Act + await RoleManager.CheckHasDomainAccess(user.Id, domainToCheck, SecurityAccess.AddUser, CancellationToken.None); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/CreateRoleUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/CreateRoleUnitTests.cs new file mode 100644 index 0000000..0c785c7 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/CreateRoleUnitTests.cs @@ -0,0 +1,287 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class CreateRoleUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CreateRole_DomainIdNotSet_ThrowsInvalidOperationException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var newRole = new CreateRole + { + + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("DomainId cannot be null")); + } + + [Test] + public void CreateRole_DomainDoesNotExist_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var newRole = new CreateRole + { + DomainId = new GeneralIdRef + { + Guid = new Guid("2f244fdd-f996-4936-872b-19b782a13e53") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Unable to find domain")); + } + + [Test] + public void CreateRole_RoleAlreadyExists_ThrowsExistsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var roleGuid = "ef8a2d5a-8842-4cc2-af5b-ef82c43b172c"; + + var role = new Role + { + Id = 234, + Guid = new Guid(roleGuid) + } ; + + RoleManagerRepository.Roles.Add(role); + + var newRole = new CreateRole + { + Guid = role.Guid, + DomainId = new GeneralIdRef + { + Guid = new Guid("2f244fdd-f996-4936-872b-19b782a13e53") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo($"Role with guid '{roleGuid}' already exists")); + } + + [Test] + public void CreateRole_RoleNameAlreadyExists_ThrowsExistsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var roleName = "My testing Role"; + + var domain = new Domain + { + Id = 1, + Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"), + Name = "Test Domain", + }; + DomainRepository.Domains.Add(domain); + + + var role = new Role + { + Id = 234, + Guid = new Guid("d95eef36-cabb-4856-b413-9f3b54375734"), + Name = roleName, + Domain = domain, + DomainId = domain.Id + }; + RoleManagerRepository.Roles.Add(role); + + var newRole = new CreateRole + { + Guid = new Guid("05b45bd7-9d87-42a9-a4c7-011c3265f5b5"), + DomainId = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = roleName + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo($"Role with name '{roleName}' already exists")); + } + + [Test] + public async Task CreateRole_EverythingOK_RoleIsCreated() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var roleName = "My testing Role"; + + var domain = new Domain + { + Id = 1, + Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"), + Name = "Test Domain", + }; + DomainRepository.Domains.Add(domain); + + var newRole = new CreateRole + { + Guid = new Guid("05b45bd7-9d87-42a9-a4c7-011c3265f5b5"), + DomainId = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = roleName + }; + + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.Roles, Has.Count.EqualTo(1)); + var actualRole = RoleManagerRepository.Roles[0]; + Assert.That(actualRole.Name, Is.EqualTo(newRole.Name)); + Assert.That(actualRole.Guid, Is.EqualTo(newRole.Guid)); + } + + [Test] + public async Task CreateRole_GuidNotSupplied_GuidIsAssigned() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var roleName = "My testing Role"; + + var domain = new Domain + { + Id = 1, + Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"), + Name = "Test Domain", + }; + DomainRepository.Domains.Add(domain); + + var newRole = new CreateRole + { + DomainId = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = roleName + }; + + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.Roles, Has.Count.EqualTo(1)); + var actualRole = RoleManagerRepository.Roles[0]; + Assert.That(actualRole.Guid, Is.Not.Null); + } + + [Test] + public async Task CreateRole_SoftDeletedRoleExists_RoleIsUnDeletedAnd() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var roleName = "My testing Role"; + + var domain = new Domain + { + Id = 1, + Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"), + Name = "Test Domain", + }; + DomainRepository.Domains.Add(domain); + + + var role = new Role + { + Id = 234, + Guid = new Guid("d95eef36-cabb-4856-b413-9f3b54375734"), + Name = roleName, + Domain = domain, + DomainId = domain.Id, + Deleted = true + }; + RoleManagerRepository.Roles.Add(role); + + var newRole = new CreateRole + { + Guid = role.Guid, + DomainId = new GeneralIdRef + { + Guid = domain.Guid + }, + Name = "Modified RoleName" + }; + + //Act + await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.RoleEdited, Is.Not.Null); + Assert.That(RoleManagerRepository.RoleEdited!.Deleted, Is.False); + Assert.That(RoleManagerRepository.RoleEdited!.Name, Is.EqualTo(newRole.Name)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleSecurityAccessUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleSecurityAccessUnitTests.cs new file mode 100644 index 0000000..d690822 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleSecurityAccessUnitTests.cs @@ -0,0 +1,99 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Security; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class DeleteRoleSecurityAccessUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + private void AddRoleAccessToFakeRepo(Role role, SecurityAccess securityAccess) + { + var roleAccess = new RoleAccess + { + Role = role, + RoleId = role.Id, + AccessKey = (int)securityAccess + }; + RoleManagerRepository.RoleAccess.Add(roleAccess); + } + + [Test] + public void DeleteRoleSecurityAccess_WhenRoleNotFound_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 09127334, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var accessToRemove = new DeleteRoleSecurityAccess + { + RoleId = new GeneralIdRef() + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.DeleteRoleSecurityAccess(auditUserDetails, accessToRemove, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Role Not Found")); + } + + [Test] + public async Task DeleteRoleSecurityAccess_WhenRoleFound_DeletesAccessForRole() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 09127334, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var role = new Role + { + Guid = new Guid("bbfb9730-37a1-4cbc-a066-4f2510adfeb4"), + Id = 234, + Name = "Testing role" + }; + RoleManagerRepository.Roles.Add(role); + + AddRoleAccessToFakeRepo(role, SecurityAccess.AddUser); + AddRoleAccessToFakeRepo(role, SecurityAccess.EditUser); + AddRoleAccessToFakeRepo(role, SecurityAccess.DeleteUser); + + var accessToRemove = new DeleteRoleSecurityAccess + { + RoleId = new GeneralIdRef + { + Guid = role.Guid + }, + SecurityAccess = new List + { + SecurityAccess.AddUser, + SecurityAccess.DeleteUser + } + }; + + //Act + await RoleManager.DeleteRoleSecurityAccess(auditUserDetails, accessToRemove, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.RoleAccess.Count, Is.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleUnitTests.cs new file mode 100644 index 0000000..5cb9e32 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleUnitTests.cs @@ -0,0 +1,85 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class DeleteRoleUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteRole_WhenRoleDoesNotExist_ThrowNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("960474cb-0443-4a9f-a0c5-1f601d1d851b") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.DeleteRole(auditUserDetails, generalIdRef, CancellationToken.None); + } + ); + + Assert.That(actualResult!.Message, Is.EqualTo("A role with this Id does not exist")); + } + + [Test] + public async Task DeleteRole_WhenExists_RoleIsSoftDeleted() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var domain = new Domain + { + Guid = new Guid("15600a5f-6b7e-4a57-bf89-00423cd25d3e"), + Id = 1234, + Name = "TestDomain" + }; + + var myTestingRole = new Role + { + Guid = new Guid("1d8331a8-51b2-4d94-b5f0-12b19beb39c8"), + Id = 1, + Name = "Role To Edit", + DomainId = domain.Id, + Domain = domain, + Deleted = false + }; + RoleManagerRepository.Roles.Add(myTestingRole); + + var generalIdRef = new GeneralIdRef() + { + Guid = myTestingRole.Guid + }; + + //Act + await RoleManager.DeleteRole(auditUserDetails, generalIdRef, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.RoleEdited, Is.Not.Null); + Assert.That(RoleManagerRepository.RoleEdited!.Deleted, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleUserUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleUserUnitTests.cs new file mode 100644 index 0000000..2dc25a7 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/DeleteRoleUserUnitTests.cs @@ -0,0 +1,128 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class DeleteRoleUserUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteRoleUser_RoleNotFound_ThrowsException() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var userRoleIds = new UserRoleIds + { + UserId = new GeneralIdRef(), + RoleId = new GeneralIdRef + { + Guid = new Guid("3511954b-a9aa-4361-ace7-0a9f5b9f0e5e") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.DeleteRoleUser(auditDetails, userRoleIds, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Role Not Found")); + } + + [Test] + public void DeleteRoleUser_RoleFoundButUserNotFound_ThrowsException() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var role = new Role + { + Guid = new Guid("491985ba-19e1-4022-a093-5e0ba93878da") + }; + RoleManagerRepository.Roles.Add(role); + + var userRoleIds = new UserRoleIds + { + UserId = new GeneralIdRef(), + RoleId = new GeneralIdRef + { + Guid = role.Guid + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.DeleteRoleUser(auditDetails, userRoleIds, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("User not Found")); + } + + [Test] + public async Task DeleteRoleUser_RoleAndUserFound_DeletesUserRole() + { + //Arrange + var auditDetails = new AuditUserDetails + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var role = new Role + { + Guid = new Guid("491985ba-19e1-4022-a093-5e0ba93878da") + }; + RoleManagerRepository.Roles.Add(role); + + var user = new User + { + Guid = new Guid("5eb2813f-27c5-4e0a-9b85-515de0d6ab37") + }; + UserManagerRepository.Users.Add(user); + + var userRoleIds = new UserRoleIds + { + UserId = new GeneralIdRef + { + Guid = user.Guid + }, + RoleId = new GeneralIdRef + { + Guid = role.Guid + } + }; + + //Act + await RoleManager.DeleteRoleUser(auditDetails, userRoleIds, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.DeleteUserRoleItem, Is.Not.Null); + Assert.That(RoleManagerRepository.DeleteUserRoleItem!.User, Is.EqualTo(user)); + Assert.That(RoleManagerRepository.DeleteUserRoleItem!.Role, Is.EqualTo(role)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/EditRoleUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/EditRoleUnitTests.cs new file mode 100644 index 0000000..bb87be8 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/EditRoleUnitTests.cs @@ -0,0 +1,170 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class EditRoleUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditRole_GeneralIsRefIsNull_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var editedRole = new EditRole + { + + }; + + //Assert + var actualResult = Assert.ThrowsAsync( async () => + { + //Act + await RoleManager.EditRole(auditUserDetails, editedRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("GeneralIdRef cannot be null")); + } + + [Test] + public void EditRole_RoleNotFound_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var editedRole = new EditRole + { + GeneralIdRef = new GeneralIdRef + { + Guid = new Guid("b6bc3c63-1d4a-4d27-b598-74dd61063a96") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.EditRole(auditUserDetails, editedRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("A role with this Id doesn't exist")); + } + + [Test] + public void EditRole_EditingRoleNameWillClashWithExistingRole_ThrowsExpectedException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var domain = new Domain + { + Guid = new Guid("15600a5f-6b7e-4a57-bf89-00423cd25d3e"), + Id = 1234, + Name = "TestDomain" + }; + + var myTestingRole = new Role + { + Guid = new Guid("1d8331a8-51b2-4d94-b5f0-12b19beb39c8"), + Id = 1, + Name = "Role To Edit", + DomainId = domain.Id, + Domain = domain + }; + RoleManagerRepository.Roles.Add(myTestingRole); + + var preExistingRole = new Role + { + Guid = new Guid("c757cbc7-a27d-40ba-afcf-c37245cbb710"), + Id = 2, + Name = "My Testing Role", + DomainId = domain.Id, + Domain = domain + }; + RoleManagerRepository.Roles.Add(preExistingRole); + + + var editedRole = new EditRole + { + GeneralIdRef = new GeneralIdRef + { + Guid = myTestingRole.Guid + }, + Name = "My Testing Role" + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await RoleManager.EditRole(auditUserDetails, editedRole, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo($"Role with name '{preExistingRole.Name}' already exists")); + } + + [Test] + public async Task EditRole_EditingRoleName_RoleNameEdited() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2562, + UserDisplayName = "Testy McTester", + }; + + var domain = new Domain + { + Guid = new Guid("15600a5f-6b7e-4a57-bf89-00423cd25d3e"), + Id = 1234, + Name = "TestDomain" + }; + + var myTestingRole = new Role + { + Guid = new Guid("1d8331a8-51b2-4d94-b5f0-12b19beb39c8"), + Id = 1, + Name = "Role To Edit", + DomainId = domain.Id, + Domain = domain + }; + RoleManagerRepository.Roles.Add(myTestingRole); + + var editedRole = new EditRole + { + GeneralIdRef = new GeneralIdRef + { + Guid = myTestingRole.Guid + }, + Name = "My Testing Role" + }; + + //Act + await RoleManager.EditRole(auditUserDetails, editedRole, CancellationToken.None); + + //Assert + Assert.That(RoleManagerRepository.RoleEdited, Is.Not.Null); + Assert.That(RoleManagerRepository.RoleEdited!.Name, Is.EqualTo(editedRole.Name)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetAccessListUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetAccessListUnitTests.cs new file mode 100644 index 0000000..8610aa6 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetAccessListUnitTests.cs @@ -0,0 +1,53 @@ +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using eSuite.Core.Security; +using NUnit.Framework; +using System.Reflection; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class GetAccessListUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetAccessList_WhenCalledWithPageZero_ReturnsCompleteAccessList() + { + //Arrange + var expectedResult = Enum.GetValues() + .Where(t => typeof(SecurityAccess).GetField(t.ToString())?.GetCustomAttribute() == null && + typeof(SecurityAccess).GetField(t.ToString())?.GetCustomAttribute() == null) + .ToList(); + expectedResult.Remove(SecurityAccess.Everyone); //This is not returned to the client, everyone gets this for free and it cannot be turned off. + + var paging = new Paging + { + Page = 0 + }; + + //Act + var actualResult = await RoleManager.GetAccessList(paging, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(actualResult, Is.Not.Null); + Assert.That(actualResult.Count, Is.EqualTo(expectedResult.Count)); + Assert.That(actualResult.Data.Count(), Is.EqualTo(expectedResult.Count)); + + foreach (var item in actualResult.Data) + { + Assert.That(item.Name.Trim().Length, Is.GreaterThan(1)); + Assert.That(item.Description.Trim().Length, Is.GreaterThan(1)); + Assert.That(item.GroupName.Trim().Length, Is.GreaterThan(1)); + Assert.That(item.SecurityAccess, Is.Not.Null); + } + Assert.That(actualResult.Data, Is.Unique); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleAccessUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleAccessUnitTests.cs new file mode 100644 index 0000000..fb37670 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleAccessUnitTests.cs @@ -0,0 +1,50 @@ +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class GetRoleAccessUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetRoleAccess_WhenCalled_ReturnsRollAccess() + { + //Arrange + var paging = new Paging + { + Page = 0 + }; + + var role = new Role + { + Id = 199, + Guid = new Guid("89458573-0495-48a8-ae21-dc4f72e52d5e"), + Name = "My Role", + IsAdministrator = false, + IsSuperUser = false + }; + + RoleManagerRepository.RoleAccess.Add( new RoleAccess + { + Role = role, + RoleId = role.Id, + AccessKey = 1, + }); + + //Act + var actualResult = await RoleManager.GetRoleAccess(paging, CancellationToken.None); + + //Assert + Assert.That(actualResult, Is.Not.Null); + Assert.That(actualResult.Count, Is.EqualTo(RoleManagerRepository.RoleAccess.Count)); + Assert.That(actualResult.Data.Count(), Is.EqualTo(RoleManagerRepository.RoleAccess.Count)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleAsyncUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleAsyncUnitTests.cs new file mode 100644 index 0000000..c521bac --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleAsyncUnitTests.cs @@ -0,0 +1,98 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class GetRoleAsyncUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetRole_RoleNotExisting_ThrowsNotFoundException() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("8d5c8114-ad04-492c-a5d3-271584763126") + }; + + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var result = await RoleManager.GetRole(generalIdRef, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Role not found")); + } + + [Test] + public void GetRole_RoleIsSoftDeleted_ThrowsNotFoundException() + { + //Arrange + var role = new Role + { + Guid = new Guid("fa863c47-d043-4e82-9daf-22ed2997e54b"), + Name = "Deleted Role", + Deleted = true + }; + RoleManagerRepository.Roles.Add(role); + + var generalIdRef = new GeneralIdRef + { + Guid = role.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var result = await RoleManager.GetRole(generalIdRef, CancellationToken.None); + }); + + Assert.That(actualResult!.Message, Is.EqualTo("Role not found")); + } + + [Test] + public async Task GetRole_WhenDomainFound_ReturnsDomain() + { + //Arrange + var domain = new Domain + { + Id = 234, + Guid = new Guid("cab894c2-9a1d-4e58-a2fd-014d0dd826a4"), + Name = "Test domain" + }; + + var role = new Role + { + Guid = new Guid("d9a2c28e-0877-44ef-852e-44243b49b8ac"), + Name = "Test role", + Domain = domain, + DomainId = domain.Id, + Deleted = false + }; + RoleManagerRepository.Roles.Add(role); + + var generalIdRef = new GeneralIdRef + { + Guid = role.Guid + }; + + //Act + var result = await RoleManager.GetRole(generalIdRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Guid, Is.EqualTo(role.Guid)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleUsersUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleUsersUnitTests.cs new file mode 100644 index 0000000..ee708aa --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRoleUsersUnitTests.cs @@ -0,0 +1,172 @@ +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class GetRoleUsersUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetRoleUsers_WhenRoleIdNull_ReturnsAllUsersForAllRoles() + { + //Arrange + var paging = new Paging(); + + var role1 = new Role + { + Guid = new Guid("c68cf187-02fe-4937-9d63-2a23586c1c1c"), + Id = 1, + Name = "Role 1", + IsAdministrator = false, + IsSuperUser = false + }; + RoleManagerRepository.Roles.Add(role1); + + var user1 = new User + { + Guid = new Guid("484382a7-4fe8-4517-8851-9f49acfb7529"), + Id = 100, + FirstName = "Testy", + LastName = "McTester", + Email = "testy@test.com" + }; + + var roleUser1 = new UserRole + { + Role = role1, + RoleId = role1.Id, + User = user1, + UserId = user1.Id + }; + RoleManagerRepository.RoleUsers.Add(roleUser1); + + var role2 = new Role + { + Guid = new Guid("adcbf8c1-96fa-4d3e-acea-573d600a3d33"), + Id = 1, + Name = "Role 2", + IsAdministrator = false, + IsSuperUser = false + }; + RoleManagerRepository.Roles.Add(role2); + + var user2 = new User + { + Guid = new Guid("c43efd35-837f-41e1-bc16-0f947e2d50ab"), + Id = 110, + FirstName = "Tested", + LastName = "McTestins", + Email = "tested@test.com" + }; + + var roleUser2 = new UserRole + { + Role = role2, + RoleId = role2.Id, + User = user2, + UserId = user2.Id + }; + RoleManagerRepository.RoleUsers.Add(roleUser2); + + var roleGeneralIdRef = new GeneralIdRef(); + + //Act + var result = await RoleManager.GetRoleUsers(paging, roleGeneralIdRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result.Data.Count(), Is.EqualTo(result.Count)); + } + + [Test] + public async Task GetRoleUsers_WhenRoleIdIsRole1_ReturnsAllUsersForRole1() + { + //Arrange + var paging = new Paging(); + + var role1 = new Role + { + Guid = new Guid("61759f40-d6c7-4cb3-9766-2339468c646d"), + Id = 1, + Name = "Role 1", + IsAdministrator = false, + IsSuperUser = false + }; + RoleManagerRepository.Roles.Add(role1); + + var user1 = new User + { + Guid = new Guid("09799a14-4c3c-49ff-a043-67a97e2d09e0"), + Id = 100, + FirstName = "Testy", + LastName = "McTester", + Email = "testy@test.com" + }; + + var roleUser1 = new UserRole + { + Role = role1, + RoleId = role1.Id, + User = user1, + UserId = user1.Id + }; + RoleManagerRepository.RoleUsers.Add(roleUser1); + + var role2 = new Role + { + Guid = new Guid("7ddfa5aa-a279-4133-85f8-2993d085caec"), + Id = 1, + Name = "Role 2", + IsAdministrator = false, + IsSuperUser = false + }; + RoleManagerRepository.Roles.Add(role2); + + var user2 = new User + { + Guid = new Guid("c68cf187-02fe-4937-9d63-2a23586c1c1c"), + Id = 110, + FirstName = "Tested", + LastName = "McTestins", + Email = "tested@test.com" + }; + + var roleUser2 = new UserRole + { + Role = role2, + RoleId = role2.Id, + User = user2, + UserId = user2.Id + }; + RoleManagerRepository.RoleUsers.Add(roleUser2); + + var roleGeneralIdRef = new GeneralIdRef + { + Guid = role1.Guid + }; + + //Act + var result = await RoleManager.GetRoleUsers(paging, roleGeneralIdRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(result.Count)); + + var returnedUser = result.Data.First(); + Assert.That(returnedUser.Id, Is.EqualTo(user1.Id)); + Assert.That(returnedUser.Guid, Is.EqualTo(user1.Guid)); + Assert.That(returnedUser.DisplayName, Is.EqualTo(user1.DisplayName)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRolesUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRolesUnitTests.cs new file mode 100644 index 0000000..e43d1a9 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/GetRolesUnitTests.cs @@ -0,0 +1,60 @@ +using e_suite.Database.Core.Tables.Domain; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class GetRolesUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetRoles_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var paging = new Paging(); + + var domain = new Domain + { + Guid = new Guid("07dd1c69-dfe7-4add-8514-a624d5c744a5"), + Name = "Testing domain" + }; + DomainRepository.Domains.Add(domain); + + var role = new Role + { + Guid = new Guid("7f986bbb-d873-42a1-aca2-7f6df6d0f26c"), + Domain = domain, + DomainId = domain.Id, + Name = "Administrator", + IsAdministrator = true, + IsSuperUser = false + }; + RoleManagerRepository.Roles.Add(role); + + var domainGeneralIdRef = new GeneralIdRef + { + Guid = domain.Guid + }; + + //Act + var result = await RoleManager.GetRoles(paging, domainGeneralIdRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + + var firstRole = result.Data.First(); + Assert.That(firstRole.Guid, Is.EqualTo(role.Guid)); + Assert.That(firstRole.Id, Is.EqualTo(role.Id)); + Assert.That(firstRole.Name, Is.EqualTo(role.Name)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/HasAnyAccessUnitTests.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/HasAnyAccessUnitTests.cs new file mode 100644 index 0000000..ea11e4d --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/HasAnyAccessUnitTests.cs @@ -0,0 +1,227 @@ +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.RoleManager.UnitTests.Helpers; +using eSuite.Core.Security; +using NUnit.Framework; + +namespace e_suite.Modules.RoleManager.UnitTests; + +[TestFixture] +public class HasAnyAccessUnitTests : RoleManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task HasAnyAccess_WhenNoAccess_ReturnsFalse() + { + //Arrange + UserManagerRepository.Users.Add(new Database.Core.Tables.UserManager.User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.AddUser); + + //Assert + Assert.That(result, Is.False); + } + + + + [Test] + public async Task HasAnyAccess_WhenUserHasExplicitAccess_ReturnsTrue() + { + //Arrange + RoleManagerRepository.UserAccess.Add( new UserAccess + { + UserId = 123, + AccessKey = (int)SecurityAccess.AddUser, + DomainId = 1 + }); + + UserManagerRepository.Users.Add(new User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.AddUser); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public async Task HasAnyAccess_WhenUserIsNotActive_ReturnsFalse() + { + //Arrange + RoleManagerRepository.UserAccess.Add(new UserAccess + { + UserId = 123, + AccessKey = (int)SecurityAccess.AddUser, + DomainId = 1, + }); + + UserManagerRepository.Users.Add(new User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1, + Active = false + }); + + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.AddUser); + + //Assert + Assert.That(result, Is.False); + } + + [Test] + public async Task HasAnyAccess_WhenAccessKeyIsEveryoneAndUserActive_ReturnsTrue() + { + //Arrange + UserManagerRepository.Users.Add(new User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.Everyone); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public async Task HasAnyAccess_WhenUserHasOtherAccess_ReturnsFalse() + { + //Arrange + RoleManagerRepository.UserAccess.Add(new UserAccess + { + UserId = 123, + AccessKey = (int)SecurityAccess.AddUser + }); + + UserManagerRepository.Users.Add(new Database.Core.Tables.UserManager.User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.EditUser); + + //Assert + Assert.That(result, Is.False); + } + + [Test] + public async Task HasAnyAccess_WhenUserIsAdministrator_ReturnsTrue() + { + //Arrange + var adminRole = new Role + { + Guid = new Guid("893de157-fc23-4505-9f1b-9a225fc2bb90"), + Id = 456, + Name = "Admin", + IsAdministrator = true, + IsSuperUser = false + }; + + UserManagerRepository.Users.Add(new Database.Core.Tables.UserManager.User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + + RoleManagerRepository.RoleUsers.Add( new UserRole + { + UserId = 123, + Role = adminRole + }); + + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.EditUser); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public async Task HasAnyAccess_WhenUserIsSuperUser_ReturnsTrue() + { + //Arrange + var adminRole = new Role + { + Guid = new Guid("893de157-fc23-4505-9f1b-9a225fc2bb90"), + Id = 456, + Name = "Admin", + IsAdministrator = false, + IsSuperUser = true + }; + + UserManagerRepository.Users.Add(new Database.Core.Tables.UserManager.User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + + RoleManagerRepository.RoleUsers.Add(new UserRole + { + UserId = 123, + Role = adminRole + }); + + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.EditUser); + + //Assert + Assert.That(result, Is.True); + } + + [Test] + public async Task HasAnyAccess_WhenUserNormalUser_ReturnsFalse() + { + //Arrange + var adminRole = new Role + { + Guid = new Guid("893de157-fc23-4505-9f1b-9a225fc2bb90"), + Id = 456, + Name = "Admin", + IsAdministrator = false, + IsSuperUser = false + }; + + UserManagerRepository.Users.Add(new Database.Core.Tables.UserManager.User + { + Id = 123, + Guid = new Guid("9698F096-1F3F-4698-8DDC-38E9CDB962CE"), + DomainId = 1 + }); + + RoleManagerRepository.RoleUsers.Add(new UserRole + { + UserId = 123, + Role = adminRole + }); + + //Act + var result = await RoleManager.HasAnyAccess(123, SecurityAccess.EditUser); + + //Assert + Assert.That(result, Is.False); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/DomainManagerTestBase.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/DomainManagerTestBase.cs new file mode 100644 index 0000000..4196e61 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/DomainManagerTestBase.cs @@ -0,0 +1,22 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; + +namespace e_suite.Modules.RoleManager.UnitTests.Helpers; + +public class RoleManagerTestBase : TestBase +{ + protected FakeRoleManagerRepository RoleManagerRepository { get; set; } = null!; + protected FakeDomainRepository DomainRepository { get; set; } = null!; + protected FakeUserManagerRepository UserManagerRepository { get; set; } = null!; + protected IRoleManager RoleManager { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + RoleManagerRepository = new FakeRoleManagerRepository(); + DomainRepository = new FakeDomainRepository(); + UserManagerRepository = new FakeUserManagerRepository(); + + RoleManager = new RoleManager(RoleManagerRepository, DomainRepository, UserManagerRepository); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeDomainRepository.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeDomainRepository.cs new file mode 100644 index 0000000..6a28585 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeDomainRepository.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace e_suite.Modules.RoleManager.UnitTests.Helpers; + +public class FakeDomainRepository : FakeRepository, IDomainRepository +{ + public List Domains = []; + + public IQueryable GetDomains() + { + throw new NotImplementedException(); + } + + public Task GetDomainById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(Domains.BuildMock().FindByGeneralIdRef(generalIdRef)); + } + + public Task GetDomainByName(string domainName, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task AddAdministratorRoleAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeRoleManagerRepository.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeRoleManagerRepository.cs new file mode 100644 index 0000000..a2477ab --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeRoleManagerRepository.cs @@ -0,0 +1,109 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace e_suite.Modules.RoleManager.UnitTests.Helpers; + +public class FakeRoleManagerRepository : FakeRepository, IRoleManagerRepository +{ + public List Roles { get; } = []; + public List RoleUsers { get; } = []; + public Role? RoleEdited { get; private set; } + + public UserRole? UserRole { get; private set; } + public UserRole? DeleteUserRoleItem { get; private set; } + + public List RoleAccess { get; } = []; + + public List UserAccess { get; } = []; + + public IQueryable GetRolesList() + { + return Roles.BuildMock(); + } + + public Task GetRoleById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(GetRolesList().FindByGeneralIdRef(generalIdRef)); + } + + public Task GetRoleByName(Domain domain, string sequenceName, CancellationToken cancellationToken) + { + return Task.FromResult(GetRolesList().SingleOrDefault(x => x.Name == sequenceName && x.DomainId == domain.Id)); + } + + public Task EditRole(AuditUserDetails auditUserDetails, Role existingSequence, CancellationToken cancellationToken) + { + RoleEdited = existingSequence; + return Task.CompletedTask; + } + + public Task AddRole(AuditUserDetails auditUserDetails, Role existingSequence, CancellationToken cancellationToken) + { + Roles.Add(existingSequence); + return Task.CompletedTask; + } + + public IQueryable GetUserRoles() + { + return RoleUsers.BuildMock(); + } + + public Task AddUserRole( + AuditUserDetails auditUserDetails, + Role existingRole, + User existingUser, + CancellationToken cancellationToken + ) + { + UserRole = new UserRole + { + Role = existingRole, + User = existingUser + }; + return Task.CompletedTask; + } + + public Task DeleteUserRole( + AuditUserDetails auditUserDetails, + Role existingRole, + User existingUser, + CancellationToken cancellationToken + ) + { + DeleteUserRoleItem = new UserRole + { + Role = existingRole, + User = existingUser + }; + return Task.CompletedTask; + } + + public IQueryable GetAccessForRole() + { + return RoleAccess.BuildMock(); + } + + public Task AddSecurityAccess(AuditUserDetails auditUserDetails, List rollAccessToAdd, CancellationToken cancellationToken) + { + RoleAccess.AddRange(rollAccessToAdd); + return Task.CompletedTask; + } + + public Task DeleteSecurityAccess(AuditUserDetails auditUserDetails, List rollAccessToDelete, CancellationToken cancellationToken) + { + foreach (var item in rollAccessToDelete) + RoleAccess.Remove(item); + return Task.CompletedTask; + } + + public IQueryable GetUserAccess() + { + return UserAccess.BuildMock(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeUserManagerRepository.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeUserManagerRepository.cs new file mode 100644 index 0000000..5418e1b --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/Helpers/FakeUserManagerRepository.cs @@ -0,0 +1,122 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace e_suite.Modules.RoleManager.UnitTests.Helpers; + +public class FakeUserManagerRepository : FakeRepository, IUserManagerRepository +{ + public List Users { get; } = []; + + public Task GetUserByEmail(string loginEmail, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetUserSsoId(long ssoId, string ssoUserId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetUserByDomainSsoId(long domainSsoId, string ssoUserId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task AddEmailUserAction( + AuditUserDetails auditUserDetails, + EmailUserAction emailConfirmation, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task AddUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetEmailUserAction(Guid token, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetCurrentEmailUserAction( + long userId, + EmailUserActionType emailUserActionType, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task DeleteEmailUserAction( + AuditUserDetails auditUserDetails, + EmailUserAction emailUserAction, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public IQueryable GetUsers() + { + return Users.BuildMock(); + } + + public Task GetUserById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(Users.SingleOrDefault(x => x.Id == generalIdRef.Id || x.Guid == generalIdRef.Guid)); + } + + public Task GetSsoProviderById(long id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public IQueryable GetSsoProviders() + { + throw new NotImplementedException(); + } + + public Task SaveSingleUseGuidForUser(SingleUseGuid singleUseGuid, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetUserBySingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task DeleteSingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetDomainById(GeneralIdRef userRegistrationDomainId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task DeleteExpiredEmailUserActions() + { + throw new NotImplementedException(); + } + + public Task DeleteExpiredSingleUseGuids() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/e-suite.Modules.RoleManager.UnitTests.csproj b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/e-suite.Modules.RoleManager.UnitTests.csproj new file mode 100644 index 0000000..646a4cc --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.UnitTests/e-suite.Modules.RoleManager.UnitTests.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + e_suite.Modules.RoleManager.UnitTests + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.sln b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.sln new file mode 100644 index 0000000..c6636f0 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.RoleManager", "e-suite.Modules.RoleManager\e-suite.Modules.RoleManager.csproj", "{2BD38B2C-B7C7-4666-ACD5-F7716D9A08AD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{C9BBC4BE-2B4F-440A-A8CD-15CB66E7B061}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{302B73E0-EFAD-4090-B228-B16B48925AF4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Modules.RoleManager.UnitTests", "e-suite.Modules.RoleManager.UnitTests\e-suite.Modules.RoleManager.UnitTests.csproj", "{0B75C34B-80A2-44C7-BDC4-29577405ADF8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2BD38B2C-B7C7-4666-ACD5-F7716D9A08AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BD38B2C-B7C7-4666-ACD5-F7716D9A08AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BD38B2C-B7C7-4666-ACD5-F7716D9A08AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BD38B2C-B7C7-4666-ACD5-F7716D9A08AD}.Release|Any CPU.Build.0 = Release|Any CPU + {0B75C34B-80A2-44C7-BDC4-29577405ADF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B75C34B-80A2-44C7-BDC4-29577405ADF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B75C34B-80A2-44C7-BDC4-29577405ADF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B75C34B-80A2-44C7-BDC4-29577405ADF8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {302B73E0-EFAD-4090-B228-B16B48925AF4} = {C9BBC4BE-2B4F-440A-A8CD-15CB66E7B061} + {0B75C34B-80A2-44C7-BDC4-29577405ADF8} = {302B73E0-EFAD-4090-B228-B16B48925AF4} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {17ECE9B0-34F0-4619-9011-2F575750B6CE} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.v3.ncrunchsolution b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/GlobalSuppressions.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/GlobalSuppressions.cs new file mode 100644 index 0000000..5eeb4c7 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "parameters in primary constructor cannot be read only.", Scope = "member", Target = "~M:e_suite.Modules.RoleManager.RoleManager.#ctor(e_suite.API.Common.repository.IRoleManagerRepository,e_suite.API.Common.repository.IDomainRepository,e_suite.API.Common.repository.IUserManagerRepository)")] diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/IocRegistration.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/IocRegistration.cs new file mode 100644 index 0000000..683f088 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.RoleManager.Repository; + +namespace e_suite.Modules.RoleManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/Repository/RoleManagerRepository.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/Repository/RoleManagerRepository.cs new file mode 100644 index 0000000..0823237 --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/Repository/RoleManagerRepository.cs @@ -0,0 +1,103 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.UserManager; + +namespace e_suite.Modules.RoleManager.Repository; + +public class RoleManagerRepository : RepositoryBase, IRoleManagerRepository +{ + public RoleManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetRolesList() + { + return DatabaseDbContext.Roles + .Include(nameof(Role.Domain)) + .Where(x => !x.Deleted); + } + + public async Task GetRoleById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Roles + .Include(nameof(Domain)) + .FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task GetRoleByName(Domain domain, string name, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Roles.Where(x => x.Name == name && x.Domain == domain).FirstOrDefaultAsync(cancellationToken); + } + + public async Task EditRole(AuditUserDetails auditUserDetails, Role role, CancellationToken cancellationToken) + { + DatabaseDbContext.Roles.Update(role); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task AddRole(AuditUserDetails auditUserDetails, Role role, CancellationToken cancellationToken) + { + await DatabaseDbContext.Roles.AddAsync(role, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public IQueryable GetUserRoles() + { + return DatabaseDbContext.UserRoles + .Include(nameof(Role)) + .Include(nameof(User)) + .Where(userRole => userRole.Deleted == false); + } + + public async Task AddUserRole(AuditUserDetails auditUserDetails, Role existingRole, User existingUser, + CancellationToken cancellationToken) + { + DatabaseDbContext.UserRoles.Add( new UserRole + { + Role = existingRole, + User = existingUser + }); + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteUserRole(AuditUserDetails auditUserDetails, Role existingRole, User existingUser, + CancellationToken cancellationToken) + { + var userRoles = GetUserRoles().Where(x => x.User == existingUser && x.Role == existingRole); + DatabaseDbContext.UserRoles.RemoveRange(userRoles); + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public IQueryable GetAccessForRole() + { + return DatabaseDbContext.RoleAccess; + } + + public async Task AddSecurityAccess(AuditUserDetails auditUserDetails, List rollAccessToAdd, CancellationToken cancellationToken) + { + await DatabaseDbContext.RoleAccess.AddRangeAsync(rollAccessToAdd, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteSecurityAccess(AuditUserDetails auditUserDetails, List rollAccessToDelete, CancellationToken cancellationToken) + { + foreach (var item in rollAccessToDelete) + { + DatabaseDbContext.RoleAccess.Remove(item); + } + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public IQueryable GetUserAccess() + { + return DatabaseDbContext.UserAccess; + } +} \ No newline at end of file diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/RoleManager.cs b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/RoleManager.cs new file mode 100644 index 0000000..cf23a5a --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/RoleManager.cs @@ -0,0 +1,554 @@ +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using System.Linq.Expressions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using eSuite.Core.Security; +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using MockQueryable; + +namespace e_suite.Modules.RoleManager; + +public class RoleManager : IRoleManager +{ + private readonly IRoleManagerRepository _roleManagerRepository; + private readonly IUserManagerRepository _userManagerRepository; + private readonly IDomainRepository _domainRepository; + + public RoleManager(IRoleManagerRepository roleManagerRepository, IDomainRepository domainRepository, IUserManagerRepository userManagerRepository) + { + _roleManagerRepository = roleManagerRepository; + _domainRepository = domainRepository; + _userManagerRepository = userManagerRepository; + } + + public async Task> GetRoles(Paging paging, IGeneralIdRef domainId, CancellationToken cancellationToken) + { + var roles = _roleManagerRepository.GetRolesList(); + + var domain = await _domainRepository.GetDomainById(domainId, cancellationToken); + + if (domain != null) + { + roles = roles.Where( role => role.Domain == domain); + } + + var paginatedData = await PaginatedData.Paginate(roles, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(ToReadRole) + + }; + + return paginatedResult; + } + + private ReadRole ToReadRole(Role role) + { + return new ReadRole + { + Id = role.Id, + Guid = role.Guid, + Name = role.Name, + CanDelete = role.CanDelete, + IsAdministrator = role.IsAdministrator, + IsSuperUser = role.IsSuperUser, + DomainId = new GeneralIdRef + { + Id = role.Domain.Id, + Guid = role.Domain.Guid + }, + DomainName = role.Domain.Name + }; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "name" => x => x.Name.Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "name" => x => x.Name, + _ => x => x.Name + }; + } + + public async Task GetRole(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var role = await _roleManagerRepository.GetRoleById(generalIdRef, cancellationToken) ?? + throw new NotFoundException("Role not found"); + + if (role.Deleted) + throw new NotFoundException("Role not found"); + + var readRole = ToReadRole(role); + + return readRole; + } + + public async Task CreateRole(AuditUserDetails auditUserDetails, CreateRole role, + CancellationToken cancellationToken) + { + await _roleManagerRepository.TransactionAsync(async () => + { + var existingRole = role.Guid == null + ? null + : await _roleManagerRepository.GetRoleById(new GeneralIdRef + { + Guid = role.Guid + }, cancellationToken); + + if (existingRole != null && !existingRole.Deleted) + throw new ExistsException($"Role with guid '{role.Guid}' already exists"); + + if (role.DomainId is null) + throw new InvalidOperationException("DomainId cannot be null"); + + var domain = await _domainRepository.GetDomainById(role.DomainId, cancellationToken) ?? + throw new NotFoundException("Unable to find domain"); + + if (existingRole == null) + { + existingRole = await _roleManagerRepository.GetRoleByName(domain, role.Name, cancellationToken); + if (existingRole != null && !existingRole.Deleted) + throw new ExistsException($"Role with name '{role.Name}' already exists"); + } + + existingRole ??= new Role + { + Guid = role.Guid ?? Guid.NewGuid() + }; + + existingRole.Name = role.Name; + existingRole.CanDelete = role.CanDelete; + existingRole.IsAdministrator = role.IsAdministrator; + existingRole.IsSuperUser = role.IsSuperUser; + existingRole.Domain = domain; + + if (existingRole.Deleted) + { + existingRole.Deleted = false; + await _roleManagerRepository.EditRole(auditUserDetails, existingRole, cancellationToken); + } + else + { + await _roleManagerRepository.AddRole(auditUserDetails, existingRole, cancellationToken); + } + }); + } + + public async Task EditRole(AuditUserDetails auditUserDetails, EditRole editRole, + CancellationToken cancellationToken) + { + await _roleManagerRepository.TransactionAsync(async () => + { + if (editRole.GeneralIdRef is null) + throw new InvalidOperationException("GeneralIdRef cannot be null"); + + var existingRole = + await _roleManagerRepository.GetRoleById(editRole.GeneralIdRef, cancellationToken); + + if (existingRole == null || existingRole.Deleted) + throw new NotFoundException("A role with this Id doesn't exist"); + + var identicalNameSequence = await _roleManagerRepository.GetRoleByName(existingRole.Domain, editRole.Name, cancellationToken); + + if (identicalNameSequence != null && (identicalNameSequence.Id != editRole.GeneralIdRef.Id && + identicalNameSequence.Guid != editRole.GeneralIdRef.Guid)) + throw new ExistsException($"Role with name '{editRole.Name}' already exists"); + + existingRole.Name = editRole.Name; + + await _roleManagerRepository.EditRole(auditUserDetails, existingRole, cancellationToken); + }); + } + + public async Task DeleteRole(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, + CancellationToken cancellationToken) + { + await _roleManagerRepository.TransactionAsync(async () => + { + var existingRole = await _roleManagerRepository.GetRoleById(generalIdRef, cancellationToken); + if (existingRole == null || existingRole.Deleted) + throw new NotFoundException("A role with this Id does not exist"); + + existingRole.Deleted = true; + + await _roleManagerRepository.EditRole(auditUserDetails, existingRole, cancellationToken); + }); + } + + public async Task> GetRoleUsers(Paging paging, GeneralIdRef roleId, CancellationToken cancellationToken) + { + var role = await _roleManagerRepository.GetRoleById(roleId, cancellationToken); + + var roleUsers = _roleManagerRepository.GetUserRoles(); + + if (role != null) + { + roleUsers = roleUsers.Where(roleUser => roleUser.Role == role); + } + + var paginatedData = await PaginatedData.Paginate(roleUsers, paging, + UserRoleKeySelector, UserRoleFilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(ToRoleUser) + + }; + + return paginatedResult; + } + + private RoleUser ToRoleUser(UserRole userRole) + { + return new RoleUser + { + Guid = userRole.User.Guid, + Id = userRole.User.Id, + DisplayName = userRole.User.DisplayName + }; + } + + private Expression> UserRoleFilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "userid" => x => x.User.Id == long.Parse(value), + "displayname" => x => ((x.User.FirstName.Trim() + " " + x.User.MiddleNames).Trim() + " " + x.User.LastName).Trim().Contains(value), + _ => x => x.Id.ToString().Contains(value), + }; + } + + private Expression> UserRoleKeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "userid" => x => x.User.DisplayName, + "displayname" => x => x.User.DisplayName, + _ => x => x.Id + }; + } + + public async Task AddRoleUser(AuditUserDetails auditUserDetails, UserRoleIds userRoleIds, + CancellationToken cancellationToken) + { + await _roleManagerRepository.TransactionAsync(async () => + { + var existingRole = await _roleManagerRepository.GetRoleById(userRoleIds.RoleId, cancellationToken); + + if (existingRole == null || existingRole.Deleted) + throw new NotFoundException("Role Not Found"); + + var existingUser = await _userManagerRepository.GetUserById(userRoleIds.UserId, cancellationToken); + + if (existingUser == null || !existingUser.Active) + throw new NotFoundException("User not Found"); + + await _roleManagerRepository.AddUserRole(auditUserDetails, existingRole, existingUser, cancellationToken); + }); + } + + public async Task DeleteRoleUser(AuditUserDetails auditUserDetails, UserRoleIds userRoleIds, + CancellationToken cancellationToken) + { + await _roleManagerRepository.TransactionAsync(async () => + { + var existingRole = await _roleManagerRepository.GetRoleById(userRoleIds.RoleId, cancellationToken); + + if (existingRole == null || existingRole.Deleted) + throw new NotFoundException("Role Not Found"); + + var existingUser = await _userManagerRepository.GetUserById(userRoleIds.UserId, cancellationToken); + + if (existingUser == null || !existingUser.Active) + throw new NotFoundException("User not Found"); + + await _roleManagerRepository.DeleteUserRole(auditUserDetails, existingRole, existingUser, cancellationToken); + }); + } + + public async Task> GetAccessList(Paging paging, CancellationToken cancellationToken) + { + var accessList = EnumerateAccessList(); + + var paginatedResult = await PaginatedData.Paginate(accessList, paging, + AccessListKeySelector, AccessListFilterSelector, cancellationToken); + + return paginatedResult; + } + + private Expression> AccessListFilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "securityaccess" => x => x.SecurityAccess.ToString().Contains(value), + "name" => x => x.Name.Contains(value), + "description" => x => x.Description.Contains(value), + "groupname" => x => x.GroupName.Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> AccessListKeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "securityaccess" => x => x.SecurityAccess, + "name" => x => x.Name, + "description" => x => x.Description, + "groupname" => x => x.GroupName, + _ => x => x.Name + }; + } + + public async Task> GetRoleAccess(Paging paging, CancellationToken cancellationToken) + { + var accessList = _roleManagerRepository.GetAccessForRole(); + + var paginatedData = await PaginatedData.Paginate(accessList, paging, + RoleAccessKeySelector, RoleAccessFilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select( + value => + { + var accessKey = (SecurityAccess)value.AccessKey; + var displayAttribute = GetEnumAttribute(accessKey); + + return new GetRoleSecurityAccess + { + RoleId = value.Role.ToGeneralIdRef()!, + SecurityAccess = accessKey, + Description = displayAttribute?.Description!, + GroupName = displayAttribute?.GroupName!, + Name = displayAttribute?.Name! + }; + } + ) + + }; + + return paginatedResult; + } + + public async Task AddRoleSecurityAccess(AuditUserDetails auditUserDetails, AddRoleSecurityAccess accessToAdd, CancellationToken cancellationToken) + { + var role = await _roleManagerRepository.GetRoleById(accessToAdd.RoleId, cancellationToken) ?? + throw new NotFoundException("Role Not Found"); + + var rollAccessToAdd = accessToAdd.SecurityAccess.Select( + securityAccess => new RoleAccess + { + Role = role, + RoleId = role.Id, + AccessKey = (int)securityAccess + } + ).ToList(); + + await _roleManagerRepository.AddSecurityAccess(auditUserDetails, rollAccessToAdd, cancellationToken); + } + + public async Task DeleteRoleSecurityAccess(AuditUserDetails auditUserDetails, + DeleteRoleSecurityAccess accessToRemove, + CancellationToken cancellationToken + ) + { + var role = await _roleManagerRepository.GetRoleById(accessToRemove.RoleId, cancellationToken) ?? + throw new NotFoundException("Role Not Found"); + + var rollAccessToDelete = _roleManagerRepository.GetAccessForRole() + .Where(x => x.RoleId == role.Id && accessToRemove.SecurityAccess.Contains( (SecurityAccess)x.AccessKey)).ToList(); + + await _roleManagerRepository.DeleteSecurityAccess(auditUserDetails, rollAccessToDelete, cancellationToken); + } + + private bool IsAdministratorInAnyDomain(User user) + { + var userRoles = _roleManagerRepository.GetUserRoles().Where(x => x.UserId == user.Id && x.Deleted == false).ToList(); + + foreach (var role in userRoles) + { + if (role.Role.IsSuperUser) //Superusers have access for all domains + return true; + + if (role.Role.IsAdministrator) //Administrators have access to all keys in their domain + return true; + } + + return false; + } + + private bool IsAdministratorInDomain(long userId, long domainId) + { + var userRoles = _roleManagerRepository.GetUserRoles().Where(x => x.UserId == userId && x.Deleted == false).ToList(); + + foreach (var role in userRoles) + { + if (role.Role.IsSuperUser) //Superusers have access for all domains + return true; + + if (role.Role.IsAdministrator && role.Role.DomainId == domainId) //Administrators have access to all keys in their domain + return true; + } + + return false; + } + + public async Task HasAnyAccess(long? userId, SecurityAccess accessKey) + { + //Next check to see if the user is a member of a role with access to the key. + var generalIdRef = new GeneralIdRef + { + Id = userId + }; + + var user = await _userManagerRepository.GetUserById(generalIdRef, CancellationToken.None) ?? + throw new NotFoundException("User Not Found"); + + if (!user.Active) + return false; + + if (accessKey == SecurityAccess.Everyone) + return true; + + var hasAccess = _roleManagerRepository.GetUserAccess().FirstOrDefault(x => x.UserId == user.Id && x.DomainId == user.DomainId && x.AccessKey == (int)accessKey); + if (hasAccess != null) + return true; + + return IsAdministratorInAnyDomain(user); + } + + public async Task CheckHasDomainAccess(long userId, IGeneralIdRef? specificDomain, SecurityAccess accessKey, CancellationToken cancellationToken) + { + var domainToCheck = await GetDomainToCheck(userId, specificDomain, cancellationToken) ?? + throw new NotFoundException("Domain Not Found"); + + var hasAccess = _roleManagerRepository + .GetUserAccess().FirstOrDefault(x => x.UserId == userId && x.DomainId == domainToCheck.Id && x.AccessKey == (int)accessKey); + + if (hasAccess != null) + return; + + if (IsAdministratorInDomain(userId, domainToCheck.Id)) + return; + + throw new UnauthorizedAccessException(); + } + + private async Task GetDomainToCheck(long userId, IGeneralIdRef? specificDomain, CancellationToken cancellationToken) + { + Domain? domainToCheck; + + if (specificDomain != null) + domainToCheck = await _domainRepository.GetDomainById(specificDomain, cancellationToken); + else + { + var user = await _userManagerRepository.GetUserById(new GeneralIdRef + { + Id = userId + }, cancellationToken); + + domainToCheck = await _domainRepository.GetDomainById(user!.Domain!.ToGeneralIdRef()!, cancellationToken); + } + + return domainToCheck; + } + + private Expression> RoleAccessFilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "roleid" => x => x.RoleId == long.Parse(value), + _ => x => x.AccessKey.ToString().Contains(value) + }; + } + + private Expression> RoleAccessKeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "roleid" => x => x.RoleId, + _ => x => x.AccessKey + }; + } + + private static IQueryable EnumerateAccessList() + { + var results = from value in Enum.GetValues() + let hiddenAttribute = GetEnumAttribute(value) + where hiddenAttribute == null + let obsoleteAttribute = GetEnumAttribute(value) + where obsoleteAttribute == null + let displayAttribute = GetEnumAttribute(value) + where displayAttribute != null + select new GetSecurityAccess + { + SecurityAccess = value, + Description = displayAttribute?.Description ?? string.Empty, + GroupName = displayAttribute?.GroupName ?? string.Empty, + Name = displayAttribute?.Name ?? value.ToString() + }; + + return results.ToList().BuildMock(); + } + + public static T? GetEnumAttribute(Enum value) where T : class + { + FieldInfo? fieldInfo = value.GetType().GetField(value.ToString()); + if (fieldInfo?.GetCustomAttributes(typeof(T), false) is T[] attributes && attributes.Length > 0) + { + return attributes.First(); + } + + return null; + } + + public IEnumerable GetMyUserAccess(User user) + { + var accessList = EnumerateAccessList(); + + if (IsAdministratorInAnyDomain(user)) +#pragma warning disable IDE0305 + return accessList.ToList(); +#pragma warning restore IDE0305 + + var userAccess = _roleManagerRepository.GetUserAccess().Where(x => x.UserId == user.Id && x.DomainId == user.DomainId) + .Select(x => (SecurityAccess)x.AccessKey) + .ToList(); + + var filteredAccessList = accessList.Where(x => userAccess.Contains(x.SecurityAccess)); + return filteredAccessList; + } +} diff --git a/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.csproj b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.csproj new file mode 100644 index 0000000..06d283f --- /dev/null +++ b/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager/e-suite.Modules.RoleManager.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + e_suite.Modules.RoleManager + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.Modules.RoleManager/nuget.config b/e-suite.Modules.RoleManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.RoleManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/.gitattributes b/e-suite.Modules.SSOManager/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.SSOManager/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/.gitignore b/e-suite.Modules.SSOManager/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.SSOManager/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.SSOManager/.runsettings b/e-suite.Modules.SSOManager/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Modules.SSOManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/README.md b/e-suite.Modules.SSOManager/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.SSOManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/Helpers/FakeSsoManagerRepository.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/Helpers/FakeSsoManagerRepository.cs new file mode 100644 index 0000000..f19d378 --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/Helpers/FakeSsoManagerRepository.cs @@ -0,0 +1,76 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace SSOManager.UnitTests.Helpers; + +public class FakeSsoManagerRepository : FakeRepository, ISsoManagerRepository +{ + public List SsoProviders = []; + + public FakeSsoManagerRepository() + { + SsoProviders.Add(new SsoProvider + { + Id = 1, + Name = "Test provider", + ClientId = "SecretClientId", + ClientSecret = "NotTellingYou", + Deleted = false, + IsPublic = true, + AuthorizationEndpoint = "AuthorizationEndpoint", + TokenEndpoint = "TokenEndpoint", + ValidIssuer = "ValidIssuer", + Guid = new Guid("{14703B56-8F70-4D9D-9061-E62EC0D446BC}") + }); + } + + public IQueryable GetSsoProviders() + { + return SsoProviders.BuildMock(); + } + + public async Task GetSsoProviderAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await GetSsoProviders().FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public Task CreateNewSsoProviderAsync( + AuditUserDetails auditUserDetails, + SsoProvider newSsoProvider, + CancellationToken cancellationToken + ) + { + if (SsoProviders.Any(x => x.Name.Equals(newSsoProvider.Name, StringComparison.InvariantCultureIgnoreCase))) + throw new Exception("SsoProvider Already exists"); + + SsoProviders.Add(newSsoProvider); + return Task.CompletedTask; + } + + public Task EditNewSsoProviderAsync( + AuditUserDetails auditUserDetails, + SsoProvider ssoProvider, + CancellationToken cancellationToken + ) + { + var realSsoProvider = SsoProviders.Single(x => x.Id == ssoProvider.Id); + + realSsoProvider.Guid = ssoProvider.Guid; + realSsoProvider.Deleted = ssoProvider.Deleted; + realSsoProvider.AuthorizationEndpoint = ssoProvider.AuthorizationEndpoint; + realSsoProvider.ClientId = ssoProvider.ClientId; + realSsoProvider.ClientSecret = ssoProvider.ClientSecret; + realSsoProvider.IsPublic = ssoProvider.IsPublic; + realSsoProvider.Name = ssoProvider.Name; + realSsoProvider.TokenEndpoint = ssoProvider.TokenEndpoint; + realSsoProvider.ValidIssuer = ssoProvider.ValidIssuer; + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/Helpers/SsoManagerTestBase.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/Helpers/SsoManagerTestBase.cs new file mode 100644 index 0000000..7a0bffe --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/Helpers/SsoManagerTestBase.cs @@ -0,0 +1,31 @@ +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.UnitTestCore; + +namespace SSOManager.UnitTests.Helpers; + +public class SsoManagerTestBase : TestBase +{ + protected FakeSsoManagerRepository SsoManagerRepository = null!; + + protected AuditUserDetails AuditUserDetails = null!; + + protected ISsoManager SsoManager = null!; + + public override async Task Setup() + { + await base.Setup(); + + AuditUserDetails = new AuditUserDetails + { + UserId = -1, + UserDisplayName = "Testing User", + Comment = "Test comment" + }; + + SsoManagerRepository = new FakeSsoManagerRepository(); + + SsoManager = new e_suite.Modules.SSOManager.SsoManager(SsoManagerRepository); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/SSOManager.UnitTests.csproj b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SSOManager.UnitTests.csproj new file mode 100644 index 0000000..2afe426 --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SSOManager.UnitTests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/AddSsoProviderAsyncUnitTests.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/AddSsoProviderAsyncUnitTests.cs new file mode 100644 index 0000000..d629c23 --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/AddSsoProviderAsyncUnitTests.cs @@ -0,0 +1,64 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using NUnit.Framework; +using SSOManager.UnitTests.Helpers; + +namespace SSOManager.UnitTests.SsoManager; + +[TestFixture] +public class AddSsoProviderAsyncUnitTests : SsoManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void AddSsoProviderAsync_WhenGuidExists_ThrowsException() + { + //Arrange + var ssoProvider = new CreateSsoProvider + { + Guid = new Guid("14703B56-8F70-4D9D-9061-E62EC0D446BC") + }; + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await SsoManager.AddSsoProviderAsync(AuditUserDetails, ssoProvider, CancellationToken.None); + }); + + Assert.That(result, Is.Not.Null); + Assert.That(result!.Message, Is.EqualTo("An SsoProvider with this guid exists")); + } + + [Test] + public async Task AddSsoProviderAsync_WhenDoesNotExist_CreatesSsoProvider() + { + //Arrange + var ssoProvider = new CreateSsoProvider + { + AuthorizationEndpoint = "authEndpoint", + ClientId = "ClientId", + ClientSecret = "It's A Secret", + Guid = new Guid("af1e8e6d-1312-41ea-99d8-20284cb7d6c6"), + IsPublic = true, + Name = "my test provider", + TokenEndpoint = "tokenEndpoint", + ValidIssuer = "myTestProvider" + }; + + //Act + await SsoManager.AddSsoProviderAsync(AuditUserDetails, ssoProvider, CancellationToken.None); + + //Assert + Assert.That(SsoManagerRepository.SsoProviders.Count, Is.EqualTo(2)); + + var newlyAddedSsoProvider = SsoManagerRepository.SsoProviders[1]; + + Assert.That(newlyAddedSsoProvider.Name, Is.EqualTo(ssoProvider.Name)); + Assert.That(newlyAddedSsoProvider.Guid, Is.EqualTo(ssoProvider.Guid)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/EditSsoProviderAsyncUnitTests.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/EditSsoProviderAsyncUnitTests.cs new file mode 100644 index 0000000..5046f63 --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/EditSsoProviderAsyncUnitTests.cs @@ -0,0 +1,162 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using SSOManager.UnitTests.Helpers; + +namespace SSOManager.UnitTests.SsoManager; + +[TestFixture] +public class EditSsoProviderAsyncUnitTests : SsoManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditSsoProviderAsyncActiveSsoProvider_WhenChangingValues_ValuesSavedCorrectly() + { + //Arrange + var ssoProvider = new SsoProvider + { + Id = 2, + Guid = new Guid("48154fbc-33ce-428e-956c-87ebcc7adc83"), + Name = "SsoProvider to Delete", + IsPublic = true, + Deleted = false, + ClientId = "ClientId", + ClientSecret = "ClientSecret", + AuthorizationEndpoint = "AuthEndPoint", + TokenEndpoint = "TokenEndpoint", + ValidIssuer = "SsoProviderToDelete" + }; + + SsoManagerRepository.SsoProviders.Add(ssoProvider); + + var editSsoProvider = new EditSsoProvider() + { + Id = new GeneralIdRef() + { + + Id = ssoProvider.Id, + Guid = ssoProvider.Guid, + } , + Name = "SsoProvider updated", + IsPublic = true, + ClientId = "UpdatedClientId", + ClientSecret = "UpdatedClientSecret", + AuthorizationEndpoint = "UpdatedAuthEndPoint", + TokenEndpoint = "UpdatedTokenEndpoint", + ValidIssuer = "UpdatedSsoProviderToDelete" + }; + + //Act + await SsoManager.EditSsoProviderAsync(AuditUserDetails, editSsoProvider, + CancellationToken.None); + + //Assert + Assert.That(ssoProvider.Deleted, Is.False); + Assert.That(ssoProvider.Name, Is.EqualTo(editSsoProvider.Name)); + Assert.That(ssoProvider.IsPublic, Is.EqualTo(editSsoProvider.IsPublic)); + Assert.That(ssoProvider.ClientId, Is.EqualTo(editSsoProvider.ClientId)); + Assert.That(ssoProvider.ClientSecret, Is.EqualTo(editSsoProvider.ClientSecret)); + Assert.That(ssoProvider.AuthorizationEndpoint, Is.EqualTo(editSsoProvider.AuthorizationEndpoint)); + Assert.That(ssoProvider.TokenEndpoint, Is.EqualTo(editSsoProvider.TokenEndpoint)); + Assert.That(ssoProvider.ValidIssuer, Is.EqualTo(editSsoProvider.ValidIssuer)); + } + + [Test] + public async Task EditSsoProviderAsyncActiveSsoProvider_WhenSettingIsPublicFalse_ValuesSavedCorrectly() + { + //Arrange + var ssoProvider = new SsoProvider + { + Id = 2, + Guid = new Guid("48154fbc-33ce-428e-956c-87ebcc7adc83"), + Name = "SsoProvider to Delete", + IsPublic = true, + Deleted = false, + ClientId = "ClientId", + ClientSecret = "ClientSecret", + AuthorizationEndpoint = "AuthEndPoint", + TokenEndpoint = "TokenEndpoint", + ValidIssuer = "SsoProviderToDelete" + }; + + SsoManagerRepository.SsoProviders.Add(ssoProvider); + + var editSsoProvider = new EditSsoProvider() + { + Id = new GeneralIdRef() + { + + Id = ssoProvider.Id, + Guid = ssoProvider.Guid, + }, + Name = "SsoProvider updated", + IsPublic = false, + ClientId = "UpdatedClientId", + ClientSecret = "UpdatedClientSecret", + AuthorizationEndpoint = "UpdatedAuthEndPoint", + TokenEndpoint = "UpdatedTokenEndpoint", + ValidIssuer = "UpdatedSsoProviderToDelete" + }; + + //Act + await SsoManager.EditSsoProviderAsync(AuditUserDetails, editSsoProvider, + CancellationToken.None); + + //Assert + Assert.That(ssoProvider.IsPublic, Is.EqualTo(editSsoProvider.IsPublic)); + } + + [Test] + public void EditSsoProviderAsyncActiveSsoProvider_WhenIdNotFound_ThrowsNotFoundException() + { + //Arrange + var ssoProvider = new SsoProvider + { + Id = 2, + Guid = new Guid("48154fbc-33ce-428e-956c-87ebcc7adc83"), + Name = "SsoProvider to Delete", + IsPublic = true, + Deleted = false, + ClientId = "ClientId", + ClientSecret = "ClientSecret", + AuthorizationEndpoint = "AuthEndPoint", + TokenEndpoint = "TokenEndpoint", + ValidIssuer = "SsoProviderToDelete" + }; + + SsoManagerRepository.SsoProviders.Add(ssoProvider); + + var editSsoProvider = new EditSsoProvider + { + Id = new GeneralIdRef + { + Id = 4, + Guid = new Guid("b537fc14-5e73-40bf-a998-07d21b65cdf9"), + }, + Name = "SsoProvider updated", + IsPublic = true, + ClientId = "UpdatedClientId", + ClientSecret = "UpdatedClientSecret", + AuthorizationEndpoint = "UpdatedAuthEndPoint", + TokenEndpoint = "UpdatedTokenEndpoint", + ValidIssuer = "UpdatedSsoProviderToDelete" + }; + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await SsoManager.EditSsoProviderAsync(AuditUserDetails, editSsoProvider, + CancellationToken.None); + }); + + Assert.That(result!.Message, Is.EqualTo("SsoProvider with this id does not exists")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/GetSsoProviderAsyncUnitTests.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/GetSsoProviderAsyncUnitTests.cs new file mode 100644 index 0000000..c7fba2c --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/GetSsoProviderAsyncUnitTests.cs @@ -0,0 +1,70 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.SSOManager.repository; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using SSOManager.UnitTests.Helpers; + +namespace SSOManager.UnitTests.SsoManager; + +[TestFixture] +public class GetSsoProviderAsyncUnitTests : SsoManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetSsoProviderAsync_WhenIdNotFound_ThrowsNotFoundException() + { + //Arrange + GeneralIdRef generalIdRef = new GeneralIdRef() + { + Guid = new Guid("24c70487-04e2-4684-bd77-55a51439d85a") + }; + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await SsoManager.GetSsoProviderAsync(generalIdRef, CancellationToken.None); + }); + + Assert.That(result, Is.Not.Null); + Assert.That(result!.Message, Is.EqualTo("Unable to find SsoProvider")); + } + + [Test] + public async Task GetSsoProviderAsync_WhenIdFound_ReturnsSsoProvider() + { + //Arrange + var ssoProvider = new SsoProvider + { + Id = 2, + Guid = new Guid("22534016-701b-4bf5-bebd-f0d638ac778e"), + Name = "Test provider", + AuthorizationEndpoint = "AuthEndPoint", + TokenEndpoint = "TokenEndPoint", + ClientId = "ClientId", + ClientSecret = "ClientSecret" + }; + + SsoManagerRepository.SsoProviders.Add(ssoProvider); + + GeneralIdRef generalIdRef = new GeneralIdRef + { + Guid = ssoProvider.Guid + }; + + + //Act + var result = await SsoManager.GetSsoProviderAsync(generalIdRef, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Id, Is.EqualTo(ssoProvider.Id)); + Assert.That(result.Guid, Is.EqualTo(ssoProvider.Guid)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/GetSsoProvidersAsyncUnitTests.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/GetSsoProvidersAsyncUnitTests.cs new file mode 100644 index 0000000..6f450d4 --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/GetSsoProvidersAsyncUnitTests.cs @@ -0,0 +1,31 @@ +using e_suite.Utilities.Pagination; +using NUnit.Framework; +using SSOManager.UnitTests.Helpers; + +namespace SSOManager.UnitTests.SsoManager; + +[TestFixture] +public class GetSsoProvidersAsyncUnitTests : SsoManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSsoProvidersAsync_WhenCalled_ReturnsRecordSet() + { + // Arrange + var paging = new Paging(); + + // Act + var result = await SsoManager.GetSsoProvidersAsync(paging, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data, Is.Not.Null); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/RemoveSsoProviderAsyncUnitTests.cs b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/RemoveSsoProviderAsyncUnitTests.cs new file mode 100644 index 0000000..8adcec5 --- /dev/null +++ b/e-suite.Modules.SSOManager/SSOManager.UnitTests/SsoManager/RemoveSsoProviderAsyncUnitTests.cs @@ -0,0 +1,62 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using SSOManager.UnitTests.Helpers; + +namespace SSOManager.UnitTests.SsoManager; + +[TestFixture] +public class RemoveSsoProviderAsyncUnitTests : SsoManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task RemoveSsoProviderAsync_ActiveSsoProvider_DeactivatesSuccessfully() + { + //Arrange + var ssoProvider = new SsoProvider + { + Id = 2, + Guid = new Guid("48154fbc-33ce-428e-956c-87ebcc7adc83"), + Name = "SsoProvider to Delete", + IsPublic = true, + Deleted = false, + ClientId = "ClientId", + ClientSecret = "ClientSecret", + AuthorizationEndpoint = "AuthEndPoint", + TokenEndpoint = "TokenEndpoint", + ValidIssuer = "SsoProviderToDelete" + }; + + SsoManagerRepository.SsoProviders.Add(ssoProvider); + + //Act + await SsoManager.RemoveSsoProviderAsync(AuditUserDetails, new GeneralIdRef { Guid = ssoProvider.Guid }, + CancellationToken.None); + + //Assert + Assert.That(ssoProvider.Deleted, Is.True); + } + + [Test] + public void RemoveSsoProviderAsync_WhenSsoProviderDoesNotExist_ThrowsException() + { + //Arrange + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await SsoManager.RemoveSsoProviderAsync(AuditUserDetails, + new GeneralIdRef { Guid = new Guid("627b0018-6e79-403e-af67-a184f1483741") }, + CancellationToken.None); + }); + + Assert.That(result!.Message, Is.EqualTo("SsoProvider with this id does not exists")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/azure-pipelines.yml b/e-suite.Modules.SSOManager/azure-pipelines.yml new file mode 100644 index 0000000..88c7211 --- /dev/null +++ b/e-suite.Modules.SSOManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.sln b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.sln new file mode 100644 index 0000000..801ec6a --- /dev/null +++ b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.34916.146 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.SSOManager", "e-suite.Modules.SSOManager\e-suite.Modules.SSOManager.csproj", "{0E38B08B-5F39-4BEE-B9E1-A1EAD7CA8D07}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{083E74A7-8842-42E8-9DE6-770BEB6AAFB3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{62D3FA34-134B-4C63-83D1-07F29F1FFF0B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSOManager.UnitTests", "SSOManager.UnitTests\SSOManager.UnitTests.csproj", "{5ACE2413-4A54-4DF3-B61E-94F539DB9BD3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0E38B08B-5F39-4BEE-B9E1-A1EAD7CA8D07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E38B08B-5F39-4BEE-B9E1-A1EAD7CA8D07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E38B08B-5F39-4BEE-B9E1-A1EAD7CA8D07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E38B08B-5F39-4BEE-B9E1-A1EAD7CA8D07}.Release|Any CPU.Build.0 = Release|Any CPU + {5ACE2413-4A54-4DF3-B61E-94F539DB9BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5ACE2413-4A54-4DF3-B61E-94F539DB9BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5ACE2413-4A54-4DF3-B61E-94F539DB9BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5ACE2413-4A54-4DF3-B61E-94F539DB9BD3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {62D3FA34-134B-4C63-83D1-07F29F1FFF0B} = {083E74A7-8842-42E8-9DE6-770BEB6AAFB3} + {5ACE2413-4A54-4DF3-B61E-94F539DB9BD3} = {62D3FA34-134B-4C63-83D1-07F29F1FFF0B} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5EE948DA-ED3F-4E8C-B48F-57CDF0A4725C} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/GlobalSuppressions.cs b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/IocRegistration.cs b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/IocRegistration.cs new file mode 100644 index 0000000..b3cc430 --- /dev/null +++ b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.SSOManager.repository; + +namespace e_suite.Modules.SSOManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/SsoManager.cs b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/SsoManager.cs new file mode 100644 index 0000000..1deef9c --- /dev/null +++ b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/SsoManager.cs @@ -0,0 +1,151 @@ +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Extensions; + +namespace e_suite.Modules.SSOManager; + +public class SsoManager : ISsoManager +{ + private readonly ISsoManagerRepository _ssoManagerRepository; + + public SsoManager(ISsoManagerRepository ssoManagerRepository) + { + _ssoManagerRepository = ssoManagerRepository; + } + + public async Task> GetSsoProvidersAsync(Paging paging, CancellationToken cancellationToken) + { + var ssoProviders = _ssoManagerRepository.GetSsoProviders().Where(x => x.Deleted == false); + + var paginatedData = await PaginatedData.Paginate(ssoProviders, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(MapSsoProvider) + }; + return paginatedResult; + } + + public async Task GetSsoProviderAsync( IGeneralIdRef generalIdRef, CancellationToken cancellationToken ) + { + var ssoProvider = await _ssoManagerRepository.GetSsoProviders().FindByGeneralIdRefAsync(generalIdRef, cancellationToken) + ?? throw new NotFoundException("Unable to find SsoProvider"); + return MapSsoProvider(ssoProvider); + } + + private ReadSsoProvider MapSsoProvider(SsoProvider ssoProvider) + { + var readSsoProvider = new ReadSsoProvider + { + Id = ssoProvider.Id, + AuthorizationEndpoint = ssoProvider.AuthorizationEndpoint, + ClientId = ssoProvider.ClientId, + ClientSecret = ssoProvider.ClientSecret, + IsPublic = ssoProvider.IsPublic, + Name = ssoProvider.Name, + TokenEndpoint = ssoProvider.TokenEndpoint, + ValidIssuer = ssoProvider.ValidIssuer, + Guid = ssoProvider.Guid + }; + + return readSsoProvider; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "name" => x => x.Name.Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "name" => x => x.Name, + _ => x => x.Name + }; + } + + public async Task AddSsoProviderAsync( + AuditUserDetails auditUserDetails, + CreateSsoProvider ssoProvider, + CancellationToken cancellationToken + ) + { + await _ssoManagerRepository.TransactionAsync(async () => + { + if (ssoProvider.Guid != null && await _ssoManagerRepository.GetSsoProviderAsync( new GeneralIdRef {Guid = ssoProvider.Guid}, cancellationToken) != null) + throw new ExistsException("An SsoProvider with this guid exists"); + + var newSsoProvider = new SsoProvider + { + Name = ssoProvider.Name, + Guid = ssoProvider.Guid ?? Guid.NewGuid(), + ClientId = ssoProvider.ClientId, + ClientSecret = ssoProvider.ClientSecret, + ValidIssuer = ssoProvider.ValidIssuer, + AuthorizationEndpoint = ssoProvider.AuthorizationEndpoint, + TokenEndpoint = ssoProvider.TokenEndpoint, + IsPublic = ssoProvider.IsPublic, + Deleted = false + }; + + await _ssoManagerRepository.CreateNewSsoProviderAsync(auditUserDetails, newSsoProvider, cancellationToken); + }); + } + + public async Task EditSsoProviderAsync( + AuditUserDetails auditUserDetails, + EditSsoProvider editSsoProvider, + CancellationToken cancellationToken + ) + { + await _ssoManagerRepository.TransactionAsync(async () => + { + var ssoProvider = await _ssoManagerRepository.GetSsoProviderAsync(editSsoProvider.Id, cancellationToken); + if (ssoProvider is null) + throw new NotFoundException("SsoProvider with this id does not exists"); + + ssoProvider.AuthorizationEndpoint = editSsoProvider.AuthorizationEndpoint; + ssoProvider.Name = editSsoProvider.Name; + ssoProvider.ClientId = editSsoProvider.ClientId; + ssoProvider.ClientSecret = editSsoProvider.ClientSecret; + ssoProvider.ValidIssuer = editSsoProvider.ValidIssuer; + ssoProvider.AuthorizationEndpoint = editSsoProvider.AuthorizationEndpoint; + ssoProvider.TokenEndpoint = editSsoProvider.TokenEndpoint; + ssoProvider.IsPublic = editSsoProvider.IsPublic; + ssoProvider.Deleted = false; + + await _ssoManagerRepository.EditNewSsoProviderAsync(auditUserDetails, ssoProvider, cancellationToken); + }); + } + + public async Task RemoveSsoProviderAsync(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + await _ssoManagerRepository.TransactionAsync(async () => + { + var ssoProvider = await _ssoManagerRepository.GetSsoProviderAsync(generalIdRef, cancellationToken); + if (ssoProvider is null) + throw new NotFoundException("SsoProvider with this id does not exists"); + + ssoProvider.Deleted = true; + await _ssoManagerRepository.EditNewSsoProviderAsync(auditUserDetails, ssoProvider, cancellationToken); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.csproj b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.csproj new file mode 100644 index 0000000..967dd40 --- /dev/null +++ b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.SSOManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/repository/SsoManagerRepository.cs b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/repository/SsoManagerRepository.cs new file mode 100644 index 0000000..5b73971 --- /dev/null +++ b/e-suite.Modules.SSOManager/e-suite.Modules.SSOManager/repository/SsoManagerRepository.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Modules.SSOManager.repository; + +public class SsoManagerRepository : RepositoryBase, ISsoManagerRepository +{ + public SsoManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetSsoProviders() + { + return DatabaseDbContext.SsoProviders; + } + + public async Task GetSsoProviderAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.SsoProviders.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task CreateNewSsoProviderAsync( + AuditUserDetails auditUserDetails, + SsoProvider newSsoProvider, + CancellationToken cancellationToken + ) + { + await DatabaseDbContext.SsoProviders.AddAsync(newSsoProvider, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditNewSsoProviderAsync( + AuditUserDetails auditUserDetails, + SsoProvider ssoProvider, + CancellationToken cancellationToken + ) + { + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SSOManager/nuget.config b/e-suite.Modules.SSOManager/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.SSOManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/.gitattributes b/e-suite.Modules.SequenceManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.SequenceManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.SequenceManager/.gitignore b/e-suite.Modules.SequenceManager/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Modules.SequenceManager/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/.runsettings b/e-suite.Modules.SequenceManager/.runsettings new file mode 100644 index 0000000..e0fd691 --- /dev/null +++ b/e-suite.Modules.SequenceManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/README.md b/e-suite.Modules.SequenceManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.SequenceManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/CreateSequenceUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/CreateSequenceUnitTests.cs new file mode 100644 index 0000000..fc2d5a2 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/CreateSequenceUnitTests.cs @@ -0,0 +1,206 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using NUnit.Framework; +using SequenceManager.UnitTests.Helpers; + + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class CreateSequenceUnitTests : SequenceManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSequence_EverythingCorrect_CreatesSequence() + { + // Arrange + var sequence = new NewSequence + { + Guid = Guid.NewGuid(), + Increment = 1, + Name = $"Sequence name {Guid.NewGuid()}", + Pattern = "Order-[000]", + RolloverType = Rollover.Continuous, + Seed = 1 + }; + + + // Act + await SequenceManager.CreateSequence(AuditUserDetails, sequence, default); + + // Assert + var createdSequence = await SequenceManagerRepository.GetSequenceByName(sequence.Name, default); + Assert.That(createdSequence, Is.Not.Null); + Assert.That(createdSequence.Name, Is.EqualTo(sequence.Name)); + Assert.That(createdSequence.Increment, Is.EqualTo(sequence.Increment)); + Assert.That(createdSequence.Guid, Is.EqualTo(sequence.Guid)); + Assert.That(createdSequence.Pattern, Is.EqualTo(sequence.Pattern)); + Assert.That(createdSequence.Seed, Is.EqualTo(sequence.Seed)); + Assert.That(createdSequence.Rollover, Is.EqualTo(sequence.RolloverType)); + } + + [Test] + public void CreateSequence_SequenceNameAlreadyExists_ThrowsException() + { + // Arrange + var guid = new Guid("{499D5186-3220-4940-80CD-36B531B6EBB7}"); + + var sequence = new NewSequence + { + Guid = guid, + Increment = 1, + Name = "Sequence exists", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + SequenceManagerRepository.Sequences.Add( new e_suite.Database.Core.Tables.Sequences.Sequence() + { + Id = 1, + Deleted = false, + Seed = 1, + Increment = 1, + Guid = new Guid("{6B14CB6F-CDBA-4724-8F77-290F76E17E48}"), + Name = sequence.Name, + Pattern = "[0]", + Rollover = Rollover.Continuous, + }); + + + // Act & Assert + Assert.ThrowsAsync(async () => + { + await SequenceManager.CreateSequence(AuditUserDetails, sequence, default); + }); + } + + [Test] + public void CreateSequence_GuidAlreadyExists_ThrowsException() + { + // Arrange + var guid = new Guid("{499D5186-3220-4940-80CD-36B531B6EBB7}"); + + var sequence = new NewSequence + { + Guid = guid, + Increment = 1, + Name = "Sequence exists", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + SequenceManagerRepository.Sequences.Add(new e_suite.Database.Core.Tables.Sequences.Sequence() + { + Id = 1, + Deleted = false, + Seed = 1, + Increment = 1, + Guid = guid, + Name = "DuplicatedName", + Pattern = "[0]", + Rollover = Rollover.Continuous, + }); + + + // Act & Assert + Assert.ThrowsAsync(async () => + { + await SequenceManager.CreateSequence(AuditUserDetails, sequence, default); + }); + } + + [Test] + public async Task CreateSequence_DeletedSequence_UndeletesSequence() + { + //Arrange + var guid = new Guid("{499D5186-3220-4940-80CD-36B531B6EBB7}"); + + var sequence = new NewSequence + { + Guid = guid, + Increment = 1, + Name = "Sequence exists", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + SequenceManagerRepository.Sequences.Add(new e_suite.Database.Core.Tables.Sequences.Sequence() + { + Id = 1, + Deleted = true, + Seed = 1, + Increment = 1, + Guid = guid, + Name = "Different Name", + Pattern = "[0]", + Rollover = Rollover.Continuous, + }); + + Assert.That(SequenceManagerRepository.Sequences.Count, Is.EqualTo(1)); + + //Act + await SequenceManager.CreateSequence(AuditUserDetails, sequence, default); + + //Assert + var actualSequence = await SequenceManagerRepository.GetSequenceById(new GeneralIdRef() { Guid = guid }, default); + + Assert.That(SequenceManagerRepository.Sequences.Count, Is.EqualTo(1)); + + Assert.That(actualSequence, Is.Not.Null); + Assert.That(actualSequence.Deleted, Is.False); + Assert.That(actualSequence.Name, Is.EqualTo(sequence.Name)); + } + + + [Test] + public async Task CreateSequence_UnDeletingSequenceUsingName_UndeletesSequence() + { + //Arrange + var guid = new Guid("{499D5186-3220-4940-80CD-36B531B6EBB7}"); + + var sequence = new NewSequence + { + Increment = 1, + Name = "Sequence exists", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + SequenceManagerRepository.Sequences.Add(new e_suite.Database.Core.Tables.Sequences.Sequence() + { + Id = 1, + Deleted = true, + Seed = 1, + Increment = 1, + Guid = guid, + Name = sequence.Name, + Pattern = "[0]", + Rollover = Rollover.Continuous, + }); + + Assert.That(SequenceManagerRepository.Sequences.Count, Is.EqualTo(1)); + + //Act + await SequenceManager.CreateSequence(AuditUserDetails, sequence, default); + + //Assert + var actualSequence = await SequenceManagerRepository.GetSequenceById(new GeneralIdRef() { Guid = guid }, default); + + Assert.That(SequenceManagerRepository.Sequences.Count, Is.EqualTo(1)); + + Assert.That(actualSequence, Is.Not.Null); + Assert.That(actualSequence.Deleted, Is.False); + Assert.That(actualSequence.Name, Is.EqualTo(sequence.Name)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/DeleteSequenceUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/DeleteSequenceUnitTests.cs new file mode 100644 index 0000000..38f735a --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/DeleteSequenceUnitTests.cs @@ -0,0 +1,95 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using NUnit.Framework; +using SequenceManager.UnitTests.Helpers; + +namespace SequenceManager.UnitTests; + +[TestFixture] +internal class DeleteSequenceUnitTests : SequenceManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteSequence_SequenceNotFound_ThrowsException() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = new Guid("{E32DAA1C-CECD-41F4-BD5E-F5AF83EF94C1}") }, + Increment = 1, + Name = "Sequence name", + Pattern = "{DD}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + // Act + // Assert + Assert.ThrowsAsync(async () => { await SequenceManager.DeleteSequence(AuditUserDetails, sequence.GeneralIdRef, default); }); + } + + [Test] + public async Task DeleteSequence_AlreadyDeleted_ThrowsException() + { + // Arrange + var sequenceGuid = new Guid("{EE90AF25-881E-4590-8A14-F351048A980A}"); + + SequenceManagerRepository.Sequences.Add(new e_suite.Database.Core.Tables.Sequences.Sequence + { + Id = 999, + Guid = sequenceGuid, + Increment = 1, + Name = "Test sequence", + Pattern = "{DD}", + Rollover = Rollover.Day, + Seed = 1 + }); + + await SequenceManager.DeleteSequence(AuditUserDetails, new GeneralIdRef { Guid = sequenceGuid }, default); + + // Act & Assert + Assert.ThrowsAsync(async () => + { + await SequenceManager.DeleteSequence(AuditUserDetails, new GeneralIdRef { Guid = sequenceGuid }, + default); + }); + } + + [Test] + public async Task DeleteSequence_EverythingOk_DeletesSequence() + { + // Arrange + var sequenceGuid = new Guid("{EE90AF25-881E-4590-8A14-F351048A980A}"); + + SequenceManagerRepository.Sequences.Add(new e_suite.Database.Core.Tables.Sequences.Sequence + { + Id = 999, + Guid = sequenceGuid, + Increment = 1, + Name = "Test sequence", + Pattern = "{DD}", + Rollover = Rollover.Day, + Seed = 1 + }); + + // Act + await SequenceManager.DeleteSequence(AuditUserDetails, new GeneralIdRef { Guid = sequenceGuid }, default); + + // Assert + var result = await SequenceManagerRepository.GetSequenceById(new GeneralIdRef { Guid = sequenceGuid }, default); + + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result?.Name, Is.EqualTo("Test sequence")); + Assert.That(result?.Deleted, Is.True); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/EditSequenceUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/EditSequenceUnitTests.cs new file mode 100644 index 0000000..5b12f48 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/EditSequenceUnitTests.cs @@ -0,0 +1,155 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using NUnit.Framework; +using SequenceManager.UnitTests.Helpers; + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class EditSequenceUnitTests : SequenceManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditSequence_SequenceNotFound_ThrowsException() + { + // Arrange + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = Guid.NewGuid() }, + Increment = 1, + Name = "Sequence name", + Pattern = "{DD}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + // Act + // Assert + Assert.ThrowsAsync(async () => { await SequenceManager.EditSequence(AuditUserDetails, sequence, default); }); + } + + [Test] + public void EditSequence_SequenceDeleted_ThrowsException() + { + // Arrange + SequenceManagerRepository.Sequences.Add( + new e_suite.Database.Core.Tables.Sequences.Sequence + { + Id = 2, + Guid = new Guid("{BCD24EAE-6232-4E07-B7FB-230E3DD8A463}"), + Increment = 1, + Name = "Existing sequence", + Pattern = "[0]", + Seed = 1, + Rollover = Rollover.Continuous, + Deleted = true + }); + + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Guid = new Guid("{BCD24EAE-6232-4E07-B7FB-230E3DD8A463}") }, + Increment = 1, + Name = "Sequence name", + Pattern = "{DD}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + + // Act + // Assert + Assert.ThrowsAsync(async () => + { + await SequenceManager.EditSequence(AuditUserDetails, sequence, default); + }); + } + + [Test] + public void EditSequence_SequenceNameAlreadyUsed_ThrowException() + { + // Arrange + SequenceManagerRepository.Sequences.Add( + new e_suite.Database.Core.Tables.Sequences.Sequence + { + Id = 1, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Test sequence", + Pattern = "[0]", + Seed = 1, + Rollover = Rollover.Continuous + }); + + SequenceManagerRepository.Sequences.Add( + new e_suite.Database.Core.Tables.Sequences.Sequence + { + Id = 2, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Existing sequence", + Pattern = "[0]", + Seed = 1, + Rollover = Rollover.Continuous + }); + + var sequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Id = 1 }, + Increment = 1, + Name = "Existing sequence", + Pattern = "{DD}", + RolloverType = Rollover.Day, + Seed = 1 + }; + + // Act + // Assert + Assert.ThrowsAsync(async () => { await SequenceManager.EditSequence(AuditUserDetails, sequence, default); }); + } + + [Test] + public async Task EditSequence_EverythingOK_SequenceIsEdited() + { + // Arrange + SequenceManagerRepository.Sequences.Add(new e_suite.Database.Core.Tables.Sequences.Sequence + { + Id = 999, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Test sequence", + Pattern = "{DD}", + Rollover = Rollover.Day, + Seed = 1 + }); + + var editSequence = new Sequence + { + GeneralIdRef = new GeneralIdRef { Id = 999 }, + Increment = 2, + Name = "Edited sequence name", + Pattern = "{MM}", + RolloverType = Rollover.Month, + Seed = 1 + }; + + // Act + await SequenceManager.EditSequence(AuditUserDetails, editSequence, default); + + // Assert + var result = await SequenceManagerRepository.GetSequenceById(new GeneralIdRef { Id = 999 }, default); + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result?.Name, Is.EqualTo(editSequence.Name)); + Assert.That(result?.Pattern, Is.EqualTo(editSequence.Pattern)); + Assert.That(result?.Rollover, Is.EqualTo(editSequence.RolloverType)); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/GetSequenceUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/GetSequenceUnitTests.cs new file mode 100644 index 0000000..6943199 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/GetSequenceUnitTests.cs @@ -0,0 +1,82 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Sequences; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using SequenceManager.UnitTests.Helpers; + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class GetSequenceUnitTests : SequenceManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetSequence_WhenSequenceDoesNotExist_ThrowsException() + { + //Arrange + var generalRefId = new GeneralIdRef + { + Guid = Guid.NewGuid(), + }; + + //Act * Assert + Assert.ThrowsAsync( async () => await SequenceManager.GetSequence(generalRefId, default) ); + } + + [Test] + public void GetSequence_WhenSequenceIsDeleted_ThrowsException() + { + //Arrange + var testGuid = new Guid("{77F925CD-C521-45D3-B8AE-00F621071989}"); + + SequenceManagerRepository.Sequences.Add(new Sequence + { + Guid = testGuid, + Id = 1, + Deleted = true, + Name = "Test Sequence" + } + ); + + var generalRefId = new GeneralIdRef + { + Guid = testGuid, + }; + + //Act * Assert + Assert.ThrowsAsync(async () => await SequenceManager.GetSequence(generalRefId, default)); + } + + [Test] + public async Task GetSequence_WhenSequenceExists_ReturnsSequenceModel() + { + //Arrange + var testGuid = new Guid("{77F925CD-C521-45D3-B8AE-00F621071989}"); + + SequenceManagerRepository.Sequences.Add( new Sequence + { + Guid = testGuid, + Id = 1, + Deleted = false, + Name = "Test Sequence" + } + ); + + var generalRefId = new GeneralIdRef + { + Guid = testGuid, + }; + + //Act + var result = await SequenceManager.GetSequence(generalRefId, default); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Name, Is.EqualTo("Test Sequence")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/GetSequencesUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/GetSequencesUnitTests.cs new file mode 100644 index 0000000..187afb4 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/GetSequencesUnitTests.cs @@ -0,0 +1,57 @@ +using e_suite.Database.Core.Tables.Sequences; +using e_suite.Utilities.Pagination; +using eSuite.Core.Sequences; +using NUnit.Framework; +using SequenceManager.UnitTests.Helpers; + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class GetSequencesUnitTests : SequenceManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSequences_Called_ReturnsSequenceList() + { + // Arrange + SequenceManagerRepository.Sequences.Add(new Sequence + { + Id = 1, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + Rollover = Rollover.Day, + Deleted = false, + Seed = 1 + }); + + SequenceManagerRepository.Sequences.Add(new Sequence + { + Id = 2, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Another sequence name", + Pattern = "Order [0000] from {DD}-{MM}-{YYYY}", + Rollover = Rollover.Day, + Deleted = false, + Seed = 1 + }); + + var paging = new Paging(); + + // Act + var sequences = await SequenceManager.GetSequences(paging, default); + + // Assert + Assert.That(sequences, Is.Not.Null); + Assert.That(sequences.Count, Is.EqualTo(2)); + Assert.That(sequences.Data, Is.Not.Null); + Assert.That(sequences.Data.Count(), Is.EqualTo(2)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/Helpers/SequenceManagerTestBase.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/Helpers/SequenceManagerTestBase.cs new file mode 100644 index 0000000..682ba61 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/Helpers/SequenceManagerTestBase.cs @@ -0,0 +1,31 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using SequenceManager.UnitTests.Repository; +using e_suite.Database.Audit; + +namespace SequenceManager.UnitTests.Helpers; + +public class SequenceManagerTestBase : TestBase +{ + protected FakeSequenceManagerRepository SequenceManagerRepository = null!; + + protected AuditUserDetails AuditUserDetails = null!; + + protected ISequenceManager SequenceManager = null!; + + public override async Task Setup() + { + await base.Setup(); + + AuditUserDetails = new AuditUserDetails + { + UserId = -1, + UserDisplayName = "Testing User", + Comment = "Test comment" + }; + + SequenceManagerRepository = new FakeSequenceManagerRepository(); + + SequenceManager = new e_suite.Modules.SequenceManager.SequenceManager(SequenceManagerRepository, _fakeClock); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/NextValueUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/NextValueUnitTests.cs new file mode 100644 index 0000000..c848018 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/NextValueUnitTests.cs @@ -0,0 +1,99 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Sequences; +using eSuite.Core.Miscellaneous; +using eSuite.Core.Sequences; +using NUnit.Framework; +using SequenceManager.UnitTests.Helpers; + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class NextValueUnitTests : SequenceManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void NextValue_SequenceNotFound_ThrowsException() + { + // Arrange + SequenceManagerRepository.Sequences.Add(new Sequence + { + Id = 555, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0]", + Rollover = Rollover.Continuous, + Deleted = false, + Seed = 0, + LastIssueDate = DateTime.Now, + LastIssueValue = 998 + }); + + // Act + // Assert + Assert.ThrowsAsync(async () => { await SequenceManager.NextValue(AuditUserDetails, new GeneralIdRef { Id = 222 }, default); }); + } + + [Test] + public void NextValue_SequenceDeleted_ThrowsException() + { + // Arrange + SequenceManagerRepository.Sequences.Add(new Sequence + { + Id = 222, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0]", + Rollover = Rollover.Continuous, + Deleted = true, + Seed = 0, + LastIssueDate = DateTime.Now, + LastIssueValue = 998 + }); + + // Act + // Assert + Assert.ThrowsAsync(async () => { await SequenceManager.NextValue(AuditUserDetails, new GeneralIdRef { Id = 222 }, default); }); + } + + [Test] + public async Task NextValue_RolloverContinous_OrderIncreases() + { + // Arrange + _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero); + + SequenceManagerRepository.Sequences.Add(new Sequence + { + Id = 555, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0] from {DD}-{MM}-{YYYY}", + Rollover = Rollover.Continuous, + Deleted = false, + Seed = 0 + }); + + // Act + var sequenceNumbers = (await SequenceManager.NextValue(AuditUserDetails, new GeneralIdRef { Id = 555 }, 10, default)).ToList(); + + // Assert + Assert.That(sequenceNumbers, !Is.Null); + Assert.That(sequenceNumbers[0], Is.EqualTo($"Order 1 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[1], Is.EqualTo($"Order 2 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[2], Is.EqualTo($"Order 3 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[3], Is.EqualTo($"Order 4 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[4], Is.EqualTo($"Order 5 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[5], Is.EqualTo($"Order 6 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[6], Is.EqualTo($"Order 7 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[7], Is.EqualTo($"Order 8 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[8], Is.EqualTo($"Order 9 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + Assert.That(sequenceNumbers[9], Is.EqualTo($"Order 10 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/Repository/FakeSequenceManagerRepository.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/Repository/FakeSequenceManagerRepository.cs new file mode 100644 index 0000000..0b9082b --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/Repository/FakeSequenceManagerRepository.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core.Tables.Sequences; +using e_suite.UnitTestCore; +using e_suite.Database.Core.Extensions; +using eSuite.Core.Miscellaneous; +using e_suite.Database.Audit; +using MockQueryable; +using MockQueryable.Moq; + +namespace SequenceManager.UnitTests.Repository; + +public class FakeSequenceManagerRepository : FakeRepository, ISequenceManagerRepository +{ + public List Sequences = []; + + public Task AddSequence(AuditUserDetails auditUserDetails, Sequence sequence, CancellationToken cancellationToken) + { + Sequences.Add(sequence); + return Task.CompletedTask; + } + + public Task EditSequence(AuditUserDetails auditUserDetails, Sequence sequence, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public async Task GetSequenceById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var sequence = Sequences.AsQueryable().FindByGeneralIdRef(generalIdRef); + return await Task.FromResult(sequence); + } + + public async Task GetSequenceByName(string Name, CancellationToken cancellationToken) + { + return await Task.FromResult(Sequences.Where(x => x.Name == Name).FirstOrDefault()); + } + + public IQueryable GetSequenceList() + { + var sequences = Sequences.Where(x => !x.Deleted).ToList().BuildMock(); + return sequences; + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/SequenceManager.UnitTests.csproj b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/SequenceManager.UnitTests.csproj new file mode 100644 index 0000000..3d4f8a9 --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/SequenceManager.UnitTests.csproj @@ -0,0 +1,27 @@ + + + + net10.0 + enable + enable + + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/SequenceNumberBuilderUnitTests.cs b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/SequenceNumberBuilderUnitTests.cs new file mode 100644 index 0000000..697b55e --- /dev/null +++ b/e-suite.Modules.SequenceManager/SequenceManager.UnitTests/SequenceNumberBuilderUnitTests.cs @@ -0,0 +1,139 @@ +using e_suite.Database.Core.Tables.Sequences; +using e_suite.Modules.SequenceManager; +using e_suite.UnitTestCore; +using eSuite.Core.Sequences; +using NUnit.Framework; +using System.Globalization; + +namespace SequenceManager.UnitTests; + +[TestFixture] +public class SequenceNumberBuilderUnitTests : TestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [TestCase("Order [0000]", $"Order 0001", 0, 1)] + [TestCase("Order [0000]", $"Order 0100", 99, 1)] + [TestCase("Order [0000]", $"Order 0000", 1, -1)] + [TestCase("Order [0000]", $"Order -0001", 0, -1)] + [TestCase("Order [0]", $"Order 999999999", 999999998, 1)] + [TestCase("Order [0]", $"Order 1", 0, 1)] + [TestCase("Order [0]", $"Order 10", 9, 1)] + public void GetNextSequenceNumber_ValueSeededAndIncrementSet_GeneratesNextSequenceNumber(string pattern, string expectedResult, long seed, long increment) + { + _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero); + + // Arrange + var sequence = new Sequence + { + Id = 555, + Guid = Guid.NewGuid(), + Increment = increment, + Name = "Sequence name", + Pattern = pattern, + Rollover = Rollover.Continuous, + Deleted = false, + Seed = seed + }; + + // Act + var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock); + + // Assert + Assert.That(sequenceNumber, !Is.Null); + Assert.That(sequenceNumber, Is.EqualTo(expectedResult)); + } + + + [Test] + public void GetNextSequenceNumber_PatternIncludesDate_DateIncludedInGeneratedSequence() + { + // Arrange + _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero); + + var sequence = new Sequence + { + Id = 555, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0] from {DD}-{MM}-{YYYY}", + Rollover = Rollover.Continuous, + Deleted = false, + Seed = 0 + }; + + // Act + var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock); + + // Assert + Assert.That(sequenceNumber, !Is.Null); + Assert.That(sequenceNumber, Is.EqualTo($"Order 1 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}")); + } + + [TestCase(Rollover.Day, "20/09/2022", "21/09/2022")] + [TestCase(Rollover.Month, "05/01/2022", "01/02/2022")] + [TestCase(Rollover.Year, "05/01/2020", "01/01/2021")] + public void GetNextSequenceNumber_RollOverSet_ValueResetsToOneAtRollover(Rollover rolloverType, string lastIssueDate, string issueDate) + { + // Arrange + var formats = new[]{ "dd/MM/yyyy" }; + _fakeClock.DateTime = DateTimeOffset.ParseExact(issueDate, formats, CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.None); + + var sequence = new Sequence + { + Id = 555, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0]", + Rollover = rolloverType, + Deleted = false, + Seed = 0, + LastIssueDate = DateTime.ParseExact(lastIssueDate, "dd/mm/yyyy", CultureInfo.InvariantCulture), + LastIssueValue = 999 + }; + + // Act + var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock); + + // Assert + Assert.That(sequenceNumber, !Is.Null); + Assert.That(sequenceNumber, Is.EqualTo("Order 1")); + } + + [TestCase(Rollover.Continuous)] + [TestCase(Rollover.Day)] + [TestCase(Rollover.Month)] + [TestCase(Rollover.Year)] + public void GetNextSequenceNumber_NotRollingOver_IssuesNextValueCorrectly(Rollover rolloverType) + { + // Arrange + _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero); + + var sequence = new Sequence + { + Id = 555, + Guid = Guid.NewGuid(), + Increment = 1, + Name = "Sequence name", + Pattern = "Order [0]", + Rollover = rolloverType, + Deleted = false, + Seed = 0, + LastIssueDate = _fakeClock.DateTime, + LastIssueValue = 998 + }; + + // Act + var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock); + + // Assert + Assert.That(sequenceNumber, !Is.Null); + Assert.That(sequenceNumber, Is.EqualTo("Order 999")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/azure-pipelines.yml b/e-suite.Modules.SequenceManager/azure-pipelines.yml new file mode 100644 index 0000000..b0aefdf --- /dev/null +++ b/e-suite.Modules.SequenceManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.SequenceManager/e-suite.Modules.SequenceManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + forceCoverageImprovement: true # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + #forceCoverageImprovement: false # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager.sln b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager.sln new file mode 100644 index 0000000..41e1610 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.SequenceManager", "e-Suite.Modules.SequenceManager\e-suite.Modules.SequenceManager.csproj", "{90DBA85E-B3F9-4B6C-9589-80A21C7CDC1E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{12CABA5F-D651-4794-A098-C2CF08242B06}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{A32B9023-74DD-4852-9766-BDF7F2D0CF91}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SequenceManager.UnitTests", "SequenceManager.UnitTests\SequenceManager.UnitTests.csproj", "{42484068-91F5-445A-BAFD-AB4351914B8C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {90DBA85E-B3F9-4B6C-9589-80A21C7CDC1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90DBA85E-B3F9-4B6C-9589-80A21C7CDC1E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90DBA85E-B3F9-4B6C-9589-80A21C7CDC1E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90DBA85E-B3F9-4B6C-9589-80A21C7CDC1E}.Release|Any CPU.Build.0 = Release|Any CPU + {42484068-91F5-445A-BAFD-AB4351914B8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42484068-91F5-445A-BAFD-AB4351914B8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42484068-91F5-445A-BAFD-AB4351914B8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42484068-91F5-445A-BAFD-AB4351914B8C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A32B9023-74DD-4852-9766-BDF7F2D0CF91} = {12CABA5F-D651-4794-A098-C2CF08242B06} + {42484068-91F5-445A-BAFD-AB4351914B8C} = {A32B9023-74DD-4852-9766-BDF7F2D0CF91} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {466402C4-8951-4D40-8874-CD594F1CDA7E} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager.v3.ncrunchsolution b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/Extensions/DateTimeExtensions.cs b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/Extensions/DateTimeExtensions.cs new file mode 100644 index 0000000..344f742 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/Extensions/DateTimeExtensions.cs @@ -0,0 +1,14 @@ +namespace e_suite.Modules.SequenceManager.Extensions; + +public static class DateTimeExtensions +{ + public static bool IsSameMonth(this DateTime dt, DateTime dateToCompare) + { + return dt.Year == dateToCompare.Year && dt.Month == dateToCompare.Month; + } + + public static bool IsSameDay(this DateTime dt, DateTime dateToCompare) + { + return dt.Year == dateToCompare.Year && dt.Month == dateToCompare.Month && dt.Day == dateToCompare.Day; + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/IocRegistration.cs b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/IocRegistration.cs new file mode 100644 index 0000000..752c371 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.SequenceManager.Repository; + +namespace e_suite.Modules.SequenceManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/Repository/SequenceManagerRepository.cs b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/Repository/SequenceManagerRepository.cs new file mode 100644 index 0000000..b3600b3 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/Repository/SequenceManagerRepository.cs @@ -0,0 +1,43 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Sequences; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.SequenceManager.Repository; + +public class SequenceManagerRepository : RepositoryBase, ISequenceManagerRepository +{ + public SequenceManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public async Task AddSequence(AuditUserDetails auditUserDetails, Sequence sequence, CancellationToken cancellationToken) + { + await DatabaseDbContext.Sequences.AddAsync(sequence, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetSequenceByName(string name, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Sequences.Where(x => x.Name == name).FirstOrDefaultAsync(cancellationToken); + } + + public async Task GetSequenceById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Sequences.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task EditSequence(AuditUserDetails auditUserDetails, Sequence sequence, CancellationToken cancellationToken) + { + DatabaseDbContext.Sequences.Update(sequence); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public IQueryable GetSequenceList() + { + return DatabaseDbContext.Sequences.Where(x => !x.Deleted); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceManager.cs b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceManager.cs new file mode 100644 index 0000000..8ae8453 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceManager.cs @@ -0,0 +1,213 @@ +using System.Diagnostics; +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Utilities.Pagination; +using eSuite.Core.Clock; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Modules.SequenceManager; + +public class SequenceManager : ISequenceManager +{ + private readonly ISequenceManagerRepository _sequenceManagerRepository; + private readonly IClock _clock; + + public SequenceManager(ISequenceManagerRepository sequenceManagerRepository, IClock clock) + { + _sequenceManagerRepository = sequenceManagerRepository; + _clock = clock; + } + + public async Task GetSequence(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var sequence = await _sequenceManagerRepository.GetSequenceById(generalIdRef, cancellationToken); + + if (sequence == null) + throw new NotFoundException(); + + if (sequence.Deleted) + throw new NotFoundException(); + + var sequenceModel = new Sequence + { + GeneralIdRef = new GeneralIdRef + { + Guid = sequence.Guid, + Id = sequence.Id + }, + Name = sequence.Name, + Pattern = sequence.Pattern, + Increment = sequence.Increment, + Seed = sequence.Seed, + RolloverType = sequence.Rollover + }; + + return sequenceModel; + } + + public async Task> GetSequences(Paging paging, CancellationToken cancellationToken) + { + var sequences = _sequenceManagerRepository.GetSequenceList(); + + var paginatedData = await PaginatedData.Paginate(sequences, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData() + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(x => new ReadSequence + { + Id = x.Id, + Guid = x.Guid, + Name = x.Name + }) + + }; + + return paginatedResult; + } + + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + _ => x => x.Name + }; + } + + public async Task CreateSequence(AuditUserDetails auditUserDetails, NewSequence sequence, CancellationToken cancellationToken) + { + await _sequenceManagerRepository.TransactionAsync(async () => + { + var existingSequence = sequence.Guid == null + ? null + : await _sequenceManagerRepository.GetSequenceById(new GeneralIdRef + { + Guid = sequence.Guid + }, cancellationToken); + + if (existingSequence != null && !existingSequence.Deleted) + throw new ExistsException($"Sequence with guid '{sequence.Guid}' already exists"); + + + if (existingSequence == null) + { + existingSequence = await _sequenceManagerRepository.GetSequenceByName(sequence.Name, cancellationToken); + if (existingSequence != null && !existingSequence.Deleted) + throw new ExistsException($"Sequence with name '{sequence.Name}' already exists"); + + } + + existingSequence ??= new Database.Core.Tables.Sequences.Sequence + { + Guid = sequence.Guid ?? Guid.NewGuid() + }; + + existingSequence.Name = sequence.Name; + existingSequence.Seed = sequence.Seed; + existingSequence.Increment = sequence.Increment; + existingSequence.Pattern = sequence.Pattern; + existingSequence.Rollover = sequence.RolloverType; + + if (existingSequence.Deleted) + { + existingSequence.Deleted = false; + await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken); + } + else + { + await _sequenceManagerRepository.AddSequence(auditUserDetails, existingSequence, cancellationToken); + } + }); + } + + public async Task EditSequence(AuditUserDetails auditUserDetails, Sequence editSequence, CancellationToken cancellationToken) + { + await _sequenceManagerRepository.TransactionAsync(async () => + { + var existingSequence = + await _sequenceManagerRepository.GetSequenceById(editSequence.GeneralIdRef!, cancellationToken); + + if (existingSequence == null || existingSequence.Deleted) + throw new NotFoundException("A sequence with this Id doesn't exist"); + + var identicalNameSequence = + await _sequenceManagerRepository.GetSequenceByName(editSequence.Name, cancellationToken); + if (identicalNameSequence != null && (identicalNameSequence.Id != editSequence.GeneralIdRef!.Id && + identicalNameSequence.Guid != editSequence.GeneralIdRef.Guid)) + throw new ExistsException($"Sequence with name '{editSequence.Name}' already exists"); + + existingSequence.Name = editSequence.Name; + existingSequence.Increment = editSequence.Increment; + existingSequence.Seed = editSequence.Seed; + existingSequence.Pattern = editSequence.Pattern; + existingSequence.Rollover = editSequence.RolloverType; + + await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken); + }); + } + + public async Task DeleteSequence(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + await _sequenceManagerRepository.TransactionAsync(async () => + { + var existingSequence = await _sequenceManagerRepository.GetSequenceById(generalIdRef, cancellationToken); + if (existingSequence == null || existingSequence.Deleted) + throw new NotFoundException("A sequence with this Id doesn't exist"); + + existingSequence.Deleted = true; + + await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken); + }); + } + + public async Task> NextValue(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, + CancellationToken cancellationToken) + { + return await NextValue( auditUserDetails, generalIdRef, 1, cancellationToken).ConfigureAwait(false); + } + + public async Task> NextValue(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, int number, CancellationToken cancellationToken) + { + return await _sequenceManagerRepository.TransactionAsync(async () => + { + var existingSequence = await _sequenceManagerRepository.GetSequenceById(generalIdRef, cancellationToken); + if (existingSequence == null || existingSequence.Deleted) + throw new NotFoundException("A sequence with this Id doesn't exist"); + + var result = new List(); + + var stopwatch = Stopwatch.StartNew(); + while (result.Count < number) + { + if (stopwatch.ElapsedMilliseconds > 2000) + throw new TimeoutException($"Took more than 2 seconds to create count list. Created {result.Count} values in the available time"); + cancellationToken.ThrowIfCancellationRequested(); + result.Add(SequenceNumberBuilder.GetNextSequenceNumber(existingSequence, _clock)); + } + + await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken); + + return result; + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceNumberBuilder.cs b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceNumberBuilder.cs new file mode 100644 index 0000000..fc8d3e9 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceNumberBuilder.cs @@ -0,0 +1,127 @@ +using e_suite.Database.Core.Tables.Sequences; +using e_suite.Modules.SequenceManager.Extensions; +using eSuite.Core.Clock; +using eSuite.Core.Sequences; +using System.Text.RegularExpressions; + +namespace e_suite.Modules.SequenceManager; + +public static class SequenceNumberBuilder +{ + private const string NumberPattern = @"\[([0-9]+)\]"; + private const string DatePattern = @"\{([MM|YY|YYYY|DD|yy|yyyy|mm|dd]+)\}"; + + private static readonly Regex NumberExpression = new(NumberPattern, RegexOptions.Compiled); + private static readonly Regex DateExpression = new(DatePattern, RegexOptions.Compiled); + + public static string GetNextSequenceNumber(Sequence sequence, IClock clock) + { + const char CustomYear = 'Y'; + const char CustomDay = 'D'; + const char CustomMonth = 'm'; + const char StandardYear = 'y'; + const char StandardDay = 'd'; + const char StandardMonth = 'M'; + const char Zero = '0'; + + var number = GenerateNumber(sequence, clock); + + var date = clock.GetNow; + var code = sequence.Pattern; + + var dateMatches = DateExpression.Matches(sequence.Pattern); + for (var index = 0; index < dateMatches.Count; index++) + { + var match = dateMatches[index]; + var dateReplacement = match.Captures[0].Value; + var dateFormat = match.Groups[1].Value; + + dateFormat = dateFormat.Replace(CustomYear, StandardYear); + dateFormat = dateFormat.Replace(CustomDay, StandardDay); + dateFormat = dateFormat.Replace(CustomMonth, StandardMonth); + + var formattedDate = date.ToString(dateFormat); + + code = code.Replace(dateReplacement, formattedDate); + } + + var numberMatches = NumberExpression.Matches(sequence.Pattern); + for (var index = 0; index < numberMatches.Count; index++) + { + var match = numberMatches[index]; + var numberReplacement = match.Captures[0].Value; + var numberFormat = match.Groups[1].Value; + + numberFormat = string.Empty.PadRight(numberFormat.Length, Zero); + var formattedNumber = number.ToString(numberFormat); + + code = code.Replace(numberReplacement, formattedNumber); + } + + return code; + } + + private static long GenerateNumber(Sequence sequence, IClock clock) + { + long number = 0; + + if (!sequence.LastIssueDate.HasValue) + { + number = sequence.Seed + sequence.Increment; + } + else + { + switch (sequence.Rollover) + { + case Rollover.Day: + if (sequence.LastIssueDate.HasValue) + { + if (sequence.LastIssueDate.Value.DateTime.IsSameDay(clock.GetNow.DateTime)) + { + number = (sequence.LastIssueValue ?? sequence.Seed) + sequence.Increment; + } + else + { + number = sequence.Seed + sequence.Increment; + } + } + break; + case Rollover.Month: + if (sequence.LastIssueDate.HasValue) + { + if (sequence.LastIssueDate.Value.DateTime.IsSameMonth(clock.GetNow.DateTime)) + { + number = (sequence.LastIssueValue ?? sequence.Seed) + sequence.Increment; + } + else + { + number = sequence.Seed + sequence.Increment; + } + } + break; + case Rollover.Year: + if (sequence.LastIssueDate.HasValue) + { + if (sequence.LastIssueDate.Value.DateTime.Year == clock.GetNow.Year) + { + number = (sequence.LastIssueValue ?? sequence.Seed) + sequence.Increment; + } + else + { + number = sequence.Seed + sequence.Increment; + } + } + break; + case Rollover.Continuous: + default: + number = (sequence.LastIssueValue ?? 0) + sequence.Increment; + break; + } + } + + sequence.LastIssueValue = number; + sequence.LastIssueDate = clock.GetNow; + + return number; + } +} \ No newline at end of file diff --git a/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/e-suite.Modules.SequenceManager.csproj b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/e-suite.Modules.SequenceManager.csproj new file mode 100644 index 0000000..014efc6 --- /dev/null +++ b/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/e-suite.Modules.SequenceManager.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + e_suite.Modules.SequenceManager + enable + enable + + + + + + + + + + + diff --git a/e-suite.Modules.SequenceManager/nuget.config b/e-suite.Modules.SequenceManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.SequenceManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/.gitattributes b/e-suite.Modules.SiteManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.SiteManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.SiteManager/.gitignore b/e-suite.Modules.SiteManager/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Modules.SiteManager/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/.runsettings b/e-suite.Modules.SiteManager/.runsettings new file mode 100644 index 0000000..e0fd691 --- /dev/null +++ b/e-suite.Modules.SiteManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/README.md b/e-suite.Modules.SiteManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.SiteManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/azure-pipelines.yml b/e-suite.Modules.SiteManager/azure-pipelines.yml new file mode 100644 index 0000000..6340077 --- /dev/null +++ b/e-suite.Modules.SiteManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/CreateSiteUnitTests.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/CreateSiteUnitTests.cs new file mode 100644 index 0000000..1e8e709 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/CreateSiteUnitTests.cs @@ -0,0 +1,241 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SiteManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.SiteManager.UnitTests; + +[TestFixture] +public class CreateSiteUnitTests : SiteManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CreateSite_SiteGuidAlreadyExists_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 21345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var site = new Site + { + Guid = new Guid("3bc0da7a-342f-48cf-883c-26a95c285bc6") + }; + SiteManagerRepository.Sites.Add(site); + + var createSite = new CreateSite + { + Guid = site.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.CreateSite(auditUserDetails, createSite, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("A site with this guid already exists")); + } + + [Test] + public void CreateSite_SiteNameInSameOrganisationAlreadyExists_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 21345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var organisation = new Organisation + { + Guid = new Guid("5da7a65a-b2e7-44d3-99b8-53608d731193"), + Id = 324652, + Name = "Testing Org" + }; + OrganisationManagerRepository.Organisations.Add(organisation); + + var site = new Site + { + Guid = new Guid("3bc0da7a-342f-48cf-883c-26a95c285bc6"), + Name = "My Site", + Organisation = organisation, + OrganisationId = organisation.Id + }; + SiteManagerRepository.Sites.Add(site); + + + var createSite = new CreateSite + { + Guid = new Guid("b459780e-e5ca-4631-ae28-4b4c177de7ab"), + Name = site.Name, + OrganisationId = new GeneralIdRef() + {Guid = organisation.Guid} + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.CreateSite(auditUserDetails, createSite, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("A site with this name already exists")); + } + + [Test] + public void CreateSite_OrganisationNotFound_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 21345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var createSite = new CreateSite + { + Guid = new Guid("2607c6f4-6d2e-41b7-a173-468c664530ee"), + OrganisationId = new GeneralIdRef + { + Guid = new Guid("60d672ef-85b0-4c86-b190-8fd24489b04e") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.CreateSite(auditUserDetails, createSite, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Organisation not found")); + } + + [Test] + public async Task CreateSite_OrganisationExists_SiteIsCreated() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 21345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var organisation = new Organisation + { + Guid = new Guid("6c06d1b2-8abe-40a2-b6ba-d5bb80ae27f7"), + Id = 2356, + Name = "Bubba Gump Shrimp Company" + }; + OrganisationManagerRepository.Organisations.Add(organisation); + + var createSite = new CreateSite + { + Guid = new Guid("2607c6f4-6d2e-41b7-a173-468c664530ee"), + OrganisationId = new GeneralIdRef + { + Guid = organisation.Guid + }, + Name = "South Carolina Dock", + Address = "End of the pier, next to the sea", + Status = OrganisationStatus.Active + }; + + //Act + await SiteManager.CreateSite(auditUserDetails, createSite, true, CancellationToken.None); + + //Assert + Assert.That(SiteManagerRepository.Sites.Count, Is.EqualTo(1)); + + var actualSite = SiteManagerRepository.Sites[0]; + Assert.That(actualSite.Guid, Is.EqualTo(createSite.Guid)); + Assert.That(actualSite.OrganisationId, Is.EqualTo(organisation.Id)); + Assert.That(actualSite.Name, Is.EqualTo(createSite.Name)); + Assert.That(actualSite.Address, Is.EqualTo(createSite.Address)); + Assert.That(actualSite.Status, Is.EqualTo(createSite.Status)); + EFlowSyncMessageSenderMock.Verify( x => x.SyncEFlowPrinterCategories(), Times.Once); + } + + [Test] + public async Task CreateSite_SiteWithSameNameCreatedInDifferentOrganisation_SiteIsCreated() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 21345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var organisation = new Organisation + { + Guid = new Guid("6c06d1b2-8abe-40a2-b6ba-d5bb80ae27f7"), + Id = 2356, + Name = "Bubba Gump Shrimp Company" + }; + OrganisationManagerRepository.Organisations.Add(organisation); + + var organisation2 = new Organisation + { + Guid = new Guid("fd15a215-2503-476b-92ac-5ac5e52173c1"), + Id = 9283475, + Name = "Pro Shrimp UK" + }; + OrganisationManagerRepository.Organisations.Add(organisation2); + + var createSite = new CreateSite + { + Guid = new Guid("2607c6f4-6d2e-41b7-a173-468c664530ee"), + OrganisationId = new GeneralIdRef + { + Guid = organisation.Guid + }, + Name = "South Carolina Dock", + Address = "End of the pier, next to the sea", + Status = OrganisationStatus.Active + }; + + var createSite2 = new CreateSite + { + Guid = new Guid("8b58c30c-873b-448a-abaa-e2e7d0d60fa7"), + OrganisationId = new GeneralIdRef + { + Guid = organisation2.Guid + }, + Name = "South Carolina Dock", + Address = "End of the pier, next to the sea, Next to Bubba Gump", + Status = OrganisationStatus.Active + }; + + await SiteManager.CreateSite(auditUserDetails, createSite, true, CancellationToken.None); + + //Act + await SiteManager.CreateSite(auditUserDetails, createSite2, true, CancellationToken.None); + + //Assert + Assert.That(SiteManagerRepository.Sites.Count, Is.EqualTo(2)); + + var actualSite = SiteManagerRepository.Sites[1]; + Assert.That(actualSite.Guid, Is.EqualTo(createSite2.Guid)); + Assert.That(actualSite.OrganisationId, Is.EqualTo(organisation2.Id)); + Assert.That(actualSite.Name, Is.EqualTo(createSite2.Name)); + Assert.That(actualSite.Address, Is.EqualTo(createSite2.Address)); + Assert.That(actualSite.Status, Is.EqualTo(createSite2.Status)); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Exactly(2)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/DeleteSiteUnitTests.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/DeleteSiteUnitTests.cs new file mode 100644 index 0000000..3990746 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/DeleteSiteUnitTests.cs @@ -0,0 +1,112 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SiteManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.SiteManager.UnitTests; + +[TestFixture] +public class DeleteSiteUnitTests : SiteManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteSite_WhenSiteDoesNotExist_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 243623, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("60e7653e-be4c-4217-8ddb-cd2a78fdadc7") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.DeleteSite(auditUserDetails, generalIdRef, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Site not found")); + } + + [Test] + public void DeleteSite_WhenSiteAlreadyDeleted_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 243623, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var site = new Site + { + Guid = new Guid("ebbe0f72-c93e-422a-806b-7c30d7f347dd"), + Id = 235, + Name = "Delete me", + Deleted = true + }; + SiteManagerRepository.Sites.Add(site); + + var generalIdRef = new GeneralIdRef + { + Guid = site.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.DeleteSite(auditUserDetails, generalIdRef, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Site already deleted")); + } + + [Test] + public async Task DeleteSite_WhenSiteNotDeleted_SiteGetsDeleted() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 243623, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var site = new Site + { + Guid = new Guid("ebbe0f72-c93e-422a-806b-7c30d7f347dd"), + Id = 235, + Name = "Delete me", + Deleted = false + }; + SiteManagerRepository.Sites.Add(site); + + var generalIdRef = new GeneralIdRef + { + Guid = site.Guid + }; + + //Act + await SiteManager.DeleteSite(auditUserDetails, generalIdRef, true, CancellationToken.None); + + //Assert + var modifiedSite = SiteManagerRepository.Sites[0]; + Assert.That(modifiedSite.Deleted, Is.True); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/EditSiteUnitTests.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/EditSiteUnitTests.cs new file mode 100644 index 0000000..0dc9eea --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/EditSiteUnitTests.cs @@ -0,0 +1,158 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SiteManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.SiteManager.UnitTests; + +[TestFixture] +public class EditSiteUnitTests : SiteManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditSite_WhenSiteNotFound_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var editSite = new EditSite + { + Id = new GeneralIdRef + { + Guid = new Guid("73d540dd-76d2-4d34-996a-88bcb3a2babe") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.EditSite(auditUserDetails, editSite, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Site not found")); + } + + [Test] + public void EditSite_MovingSiteFromOneOrganisationToAnother_ThrowsException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var organisation = new Organisation + { + Guid = new Guid("e2b4ddd3-6746-4e13-ab2a-8f151357d92f"), + Id = 2235412, + Name = "My Organisation" + }; + + var site = new Site + { + Guid = new Guid("32622e33-a43f-4eef-82b6-fcb4beb76631"), + Id = 2356, + Name = "I R Gud speln", + Address = "Near the place", + Organisation = organisation, + OrganisationId = organisation.Id, + Status = OrganisationStatus.Active + }; + SiteManagerRepository.Sites.Add(site); + + var editSite = new EditSite + { + Id = new GeneralIdRef + { + Guid = site.Guid + }, + OrganisationId = new GeneralIdRef + { + Guid = new Guid("9109af41-a615-4a60-9615-a7c9e1a90547") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SiteManager.EditSite(auditUserDetails, editSite, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Not allow to move a site from one organisation to another")); + } + + [Test] + public async Task EditSite_EditIsOK_SiteIsEditedAsExpected() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var organisation = new Organisation + { + Guid = new Guid("e2b4ddd3-6746-4e13-ab2a-8f151357d92f"), + Id = 2235412, + Name = "My Organisation" + }; + + var site = new Site + { + Guid = new Guid("32622e33-a43f-4eef-82b6-fcb4beb76631"), + Id = 2356, + Name = "I R Gud speln", + Address = "Near the place", + Organisation = organisation, + OrganisationId = organisation.Id, + Status = OrganisationStatus.Active + }; + SiteManagerRepository.Sites.Add(site); + + var editSite = new EditSite + { + Id = new GeneralIdRef + { + Guid = site.Guid + }, + OrganisationId = new GeneralIdRef + { + Guid = organisation.Guid + }, + Name = "I am good at spelling", + Address = "Second window on the left, next to the doorway", + Status = OrganisationStatus.Pending + }; + + //Act + await SiteManager.EditSite(auditUserDetails, editSite, true, CancellationToken.None); + + //Assert + Assert.That( SiteManagerRepository.EditedSite, Is.Not.Null); + Assert.That(SiteManagerRepository.EditedSite.Guid, Is.EqualTo(site.Guid)); + Assert.That(SiteManagerRepository.EditedSite.Id, Is.EqualTo(site.Id)); + Assert.That(SiteManagerRepository.EditedSite.Name, Is.EqualTo(editSite.Name)); + Assert.That(SiteManagerRepository.EditedSite.Address, Is.EqualTo(editSite.Address)); + Assert.That(SiteManagerRepository.EditedSite.Status, Is.EqualTo(editSite.Status)); + EFlowSyncMessageSenderMock.Verify( x => x.SyncEFlowPrinterCategories(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/GetSiteUnitTests.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/GetSiteUnitTests.cs new file mode 100644 index 0000000..ef0b990 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/GetSiteUnitTests.cs @@ -0,0 +1,81 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SiteManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.SiteManager.UnitTests; + +[TestFixture] +public class GetSiteUnitTests : SiteManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetSite_SiteNotFound_ThrowsException() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("9bd47040-8124-47fb-aac8-e3e02c02a1a5") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var actualResult = await SiteManager.GetSite(generalIdRef, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Site not found")); + } + + [Test] + public async Task GetSite_SiteExists_ReturnsSite() + { + //Arrange + var organisation = new Organisation + { + Guid = new Guid("80db1d8b-5bdd-45e3-b6b8-86d99aa3fc74"), + Id = 2356, + Name = "Test organisation LLC", + Status = OrganisationStatus.Pending + }; + + var site = new Site + { + Guid = new Guid("949c4b6e-16cb-44c9-8441-1465977f2ce3"), + Id = 21351, + Name = "Testing site", + Organisation = organisation, + OrganisationId = organisation.Id, + Status = OrganisationStatus.Active + }; + SiteManagerRepository.Sites.Add(site); + + var generalIdRef = new GeneralIdRef + { + Guid = site.Guid + }; + + //Act + var actualResult = await SiteManager.GetSite(generalIdRef, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(actualResult, Is.Not.Null); + Assert.That(actualResult.Guid, Is.EqualTo(site.Guid)); + Assert.That(actualResult.Id, Is.EqualTo(site.Id)); + Assert.That(actualResult.Address, Is.EqualTo(site.Address)); + Assert.That(actualResult.Name, Is.EqualTo(site.Name)); + Assert.That(actualResult.Status, Is.EqualTo(site.Status)); + Assert.That(actualResult.OrganisationId.Guid, Is.EqualTo(organisation.Guid)); + Assert.That(actualResult.OrganisationId.Id, Is.EqualTo(organisation.Id)); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/GetSitesUnitTests.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/GetSitesUnitTests.cs new file mode 100644 index 0000000..c7ed76c --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/GetSitesUnitTests.cs @@ -0,0 +1,56 @@ +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SiteManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.SiteManager.UnitTests; + +[TestFixture] +public class GetSitesUnitTests : SiteManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSites_WhenCalled_ReturnsExpectedResult() + { + //Arrange + var paging = new Paging(); + + var organisation = new Organisation + { + Guid = new Guid("0bed12bd-3cce-4dda-aa1f-8796a1edcc80"), + Id = 12345, + Name = "Test Organisation" + }; + + var site = new Site + { + Guid = new Guid("b85c48bb-1dc3-4d60-aae6-888f8c90073d"), + Id = 21354, + Name = "Test Site", + Status = OrganisationStatus.Active, + Address = "123 Somewhere street", + Organisation = organisation, + OrganisationId = organisation.Id + }; + SiteManagerRepository.Sites.Add(site); + + //Act + var result = await SiteManager.GetSites(paging, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + + var firstSite = result.Data.First(); + Assert.That(firstSite.Guid, Is.EqualTo(site.Guid)); + Assert.That(firstSite.Id, Is.EqualTo(site.Id)); + Assert.That(firstSite.Name, Is.EqualTo(site.Name)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/FakeOrganisationManagerRepository.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/FakeOrganisationManagerRepository.cs new file mode 100644 index 0000000..85a44ba --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/FakeOrganisationManagerRepository.cs @@ -0,0 +1,48 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.SiteManager.UnitTests.Helpers; + +public class FakeOrganisationManagerRepository : FakeRepository, IOrganisationsManagerRepository +{ + public List Organisations { get; set; } = []; + + public IQueryable GetOrganisationsList() + { + return Organisations.BuildMock(); + } + + public Task AddOrganisation(AuditUserDetails auditUserDetails, Organisation organisation, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task DeleteOrganisation( + AuditUserDetails auditUserDetails, + IGeneralIdRef generalIdRef, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task EditOrganisation( + AuditUserDetails auditUserDetails, + Organisation organisation, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public async Task FindOrganisation(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await GetOrganisationsList().FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/FakeSiteManagerRepository.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/FakeSiteManagerRepository.cs new file mode 100644 index 0000000..ee2fe16 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/FakeSiteManagerRepository.cs @@ -0,0 +1,51 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.SiteManager.UnitTests.Helpers; + +public class FakeSiteManagerRepository : FakeRepository, ISiteManagerRepository +{ + public List Sites { get; set; } = []; + + public Site EditedSite { get; private set; } = null!; + + public IQueryable GetSites() + { + return Sites.BuildMock(); + } + + public Task GetSite(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(GetSites().FindByGeneralIdRef(generalIdRef)); + } + + public Task GetSite(long sigmaId, CancellationToken cancellationToken) + { + return Task.FromResult(GetSites().SingleOrDefault(x => x.SigmaId == sigmaId)); + } + + public Task EditSite(AuditUserDetails auditUserDetails, Site editedSite, CancellationToken cancellationToken) + { + EditedSite = editedSite; + return Task.CompletedTask; + } + + + public Task CreateSite(AuditUserDetails auditUserDetails, Site newSite, CancellationToken cancellationToken) + { + Sites.Add(newSite); + return Task.CompletedTask; + } + + public Task CreateSite(AuditUserDetails auditUserDetails, IEnumerable newSites, CancellationToken cancellationToken) + { + Sites.AddRange(newSites); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/SiteManagerTestBase.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/SiteManagerTestBase.cs new file mode 100644 index 0000000..f3afb04 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/Helpers/SiteManagerTestBase.cs @@ -0,0 +1,25 @@ +using e_suite.API.Common; +using e_suite.Messaging.Common; +using e_suite.UnitTestCore; +using Moq; + +namespace e_suite.Modules.SiteManager.UnitTests.Helpers; + +public class SiteManagerTestBase : TestBase +{ + protected FakeSiteManagerRepository SiteManagerRepository { get; set; } = null!; + protected FakeOrganisationManagerRepository OrganisationManagerRepository { get; set; } = null!; + protected Mock EFlowSyncMessageSenderMock { get; set; } = null!; + protected ISiteManager SiteManager { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + SiteManagerRepository = new FakeSiteManagerRepository(); + OrganisationManagerRepository = new FakeOrganisationManagerRepository(); + EFlowSyncMessageSenderMock = new Mock(); + + SiteManager = new SiteManager(SiteManagerRepository, OrganisationManagerRepository, EFlowSyncMessageSenderMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/e-suite.Modules.SiteManager.UnitTests.csproj b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/e-suite.Modules.SiteManager.UnitTests.csproj new file mode 100644 index 0000000..d494be0 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.UnitTests/e-suite.Modules.SiteManager.UnitTests.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + e_suite.Modules.SiteManager.UnitTests + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.sln b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.sln new file mode 100644 index 0000000..52eca28 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.SiteManager", "e-suite.Modules.SiteManager\e-suite.Modules.SiteManager.csproj", "{17AA8679-7AF2-4AB8-8FAE-F8437E8DE609}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8FEBDC57-0F09-4507-A530-5E2D0287354B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{5FC28152-2408-4EC6-9993-BC8B999AECA3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Modules.SiteManager.UnitTests", "e-suite.Modules.SiteManager.UnitTests\e-suite.Modules.SiteManager.UnitTests.csproj", "{CE0650B5-35C4-4B73-ABB2-FD6C5DA0BAB5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {17AA8679-7AF2-4AB8-8FAE-F8437E8DE609}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17AA8679-7AF2-4AB8-8FAE-F8437E8DE609}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17AA8679-7AF2-4AB8-8FAE-F8437E8DE609}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17AA8679-7AF2-4AB8-8FAE-F8437E8DE609}.Release|Any CPU.Build.0 = Release|Any CPU + {CE0650B5-35C4-4B73-ABB2-FD6C5DA0BAB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE0650B5-35C4-4B73-ABB2-FD6C5DA0BAB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE0650B5-35C4-4B73-ABB2-FD6C5DA0BAB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE0650B5-35C4-4B73-ABB2-FD6C5DA0BAB5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {5FC28152-2408-4EC6-9993-BC8B999AECA3} = {8FEBDC57-0F09-4507-A530-5E2D0287354B} + {CE0650B5-35C4-4B73-ABB2-FD6C5DA0BAB5} = {5FC28152-2408-4EC6-9993-BC8B999AECA3} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9DE9C46F-95DB-417C-8525-47F6B30AD54F} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.sln.DotSettings b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.sln.DotSettings new file mode 100644 index 0000000..2bba4c4 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.v3.ncrunchsolution b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/GlobalSuppressions.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/GlobalSuppressions.cs new file mode 100644 index 0000000..9633a17 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/IocRegistration.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/IocRegistration.cs new file mode 100644 index 0000000..1e74683 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.SiteManager.repository; + +namespace e_suite.Modules.SiteManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/SiteManager.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/SiteManager.cs new file mode 100644 index 0000000..99a439f --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/SiteManager.cs @@ -0,0 +1,203 @@ +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Messaging.Common; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.SiteManager; + +public class SiteManager : ISiteManager +{ + private readonly ISiteManagerRepository _siteManagerRepository; + private readonly IOrganisationsManagerRepository _organisationManagerRepository; + private readonly IEFlowSyncMessageSender _eFlowSyncMessageSender; + + public SiteManager(ISiteManagerRepository siteManagerRepository, IOrganisationsManagerRepository organisationManagerRepository, IEFlowSyncMessageSender eFlowSyncMessageSender) + { + _siteManagerRepository = siteManagerRepository; + _organisationManagerRepository = organisationManagerRepository; + _eFlowSyncMessageSender = eFlowSyncMessageSender; + } + + private static void Assert(T? item, string message = "Site not found") where T : ISoftDeletable + { + if (item == null || item.Deleted) + { + throw new NotFoundException(message); + } + } + + public async Task> GetSites(Paging paging, CancellationToken cancellationToken) + { + var forms = _siteManagerRepository.GetSites(); + + + var paginatedData = await PaginatedData.Paginate(forms, paging, + KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(MapSite) + }; + return paginatedResult; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "organisationid" => x => x.OrganisationId.ToString() == value, + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "organisationid" => x => x.OrganisationId, + _ => x => x.Name + }; + } + + private static ReadSite MapSite(Site site) + { + return new ReadSite + { + Id = site.Id, + Guid = site.Guid, + Name = site.Name, + Address = site.Address, + Status = site.Status, + SigmaId = site.SigmaId, + OrganisationId = new GeneralIdRef + { + Id = site.Organisation.Id, + Guid = site.Organisation.Guid + } + }; + } + + public async Task GetSite(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var site = await _siteManagerRepository.GetSite(generalIdRef, cancellationToken); + Assert(site); + return MapSite(site!); + } + + public async Task GetSiteBySigmaId(long sigmaId, CancellationToken cancellationToken) + { + var site = await _siteManagerRepository.GetSite(sigmaId, cancellationToken); + Assert(site); + return MapSite(site!); + } + + + public async Task GetSiteByName(IGeneralIdRef organisationGeneralIdRef, string siteName, CancellationToken cancellationToken) + { + var organisation = await _organisationManagerRepository.FindOrganisation(organisationGeneralIdRef, cancellationToken) ?? throw new ArgumentException("Unable to find organisation", nameof(organisationGeneralIdRef)); + var site = await _siteManagerRepository.GetSites().Where( x => x.Organisation == organisation && x.Name.Equals(siteName)).SingleOrDefaultAsync(cancellationToken) ?? throw new NotFoundException("Unable to find site by name"); + Assert(site); + return MapSite(site!); + } + + public async Task CreateSite(AuditUserDetails auditUserDetails, CreateSite site, + bool triggerEFlowSync, CancellationToken cancellationToken) + { + await CreateSites(auditUserDetails, [site], triggerEFlowSync, cancellationToken); + } + + public async Task CreateSites(AuditUserDetails auditUserDetails, IEnumerable sites, bool triggerEFlowSync, CancellationToken cancellationToken) + { + await _siteManagerRepository.TransactionAsync(async () => + { + var newSites = new List(); + + foreach (var site in sites) + { + if (site.Guid != null && + await _siteManagerRepository.GetSite(new GeneralIdRef { Guid = site.Guid }, cancellationToken) != + null) + throw new ExistsException("A site with this guid already exists"); + + var organisation = + await _organisationManagerRepository.FindOrganisation(site.OrganisationId, cancellationToken); + Assert(organisation, "Organisation not found"); + + if (await _siteManagerRepository.GetSites() + .FirstOrDefaultAsync(x => x.Name == site.Name && x.OrganisationId == organisation!.Id, + cancellationToken) != null) + throw new ExistsException("A site with this name already exists"); + + var newSite = new Site + { + Name = site.Name, + Address = site.Address, + Status = site.Status, + Organisation = organisation!, + OrganisationId = organisation!.Id, + SigmaId = site.SigmaId, + Guid = site.Guid ?? Guid.NewGuid() + }; + + newSites.Add(newSite); + } + + await _siteManagerRepository.CreateSite(auditUserDetails, newSites, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + }); + } + + public async Task EditSite(AuditUserDetails auditUserDetails, EditSite site, bool triggerEFlowSync, CancellationToken cancellationToken) + { + await _siteManagerRepository.TransactionAsync(async () => + { + var siteOriginal = await _siteManagerRepository.GetSite(site.Id, cancellationToken); + Assert(siteOriginal); + siteOriginal!.Name = site.Name; + siteOriginal!.Address = site.Address; + siteOriginal!.Status = site.Status; + siteOriginal!.SigmaId = site.SigmaId; + + if (!siteOriginal.Organisation.IsMatch(site.OrganisationId)) + throw new InvalidOperationException("Not allow to move a site from one organisation to another"); + + await _siteManagerRepository.EditSite(auditUserDetails, siteOriginal, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + }); + } + + public async Task DeleteSite(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, bool triggerEFlowSync, CancellationToken cancellationToken) + { + await _siteManagerRepository.TransactionAsync(async () => + { + var formTemplate = await _siteManagerRepository.GetSite(generalIdRef, cancellationToken) ?? + throw new NotFoundException("Site not found"); + + if (formTemplate.Deleted) + throw new InvalidOperationException("Site already deleted"); + + formTemplate.Deleted = true; + await _siteManagerRepository.EditSite(auditUserDetails, formTemplate, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.csproj b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.csproj new file mode 100644 index 0000000..1fc6495 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.SiteManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/repository/SiteManagerRepository.cs b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/repository/SiteManagerRepository.cs new file mode 100644 index 0000000..80d2730 --- /dev/null +++ b/e-suite.Modules.SiteManager/e-suite.Modules.SiteManager/repository/SiteManagerRepository.cs @@ -0,0 +1,59 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.SiteManager.repository; + +public class SiteManagerRepository : RepositoryBase, ISiteManagerRepository +{ + public SiteManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetSites() + { + return DatabaseDbContext.Sites + .Include( x=> x.Organisation) + .Where(x => x.Deleted == false); + } + + public async Task GetSite(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await GetSites().FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task GetSite(long sigmaId, CancellationToken cancellationToken) + { + return await GetSites().SingleOrDefaultAsync(x => x.SigmaId == sigmaId, cancellationToken); + } + + public async Task EditSite(AuditUserDetails auditUserDetails, Site editedSite, CancellationToken cancellationToken) + { + DatabaseDbContext.Sites.Update(editedSite); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task CreateSite(AuditUserDetails auditUserDetails, Site newSite, CancellationToken cancellationToken) + { + var newSites = new List + { + newSite + }; + + await CreateSite(auditUserDetails, newSites, cancellationToken); + } + + public async Task CreateSite(AuditUserDetails auditUserDetails, IEnumerable newSites, CancellationToken cancellationToken) + { + foreach (var newSite in newSites) + { + DatabaseDbContext.Sites.Add(newSite); + } + + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SiteManager/nuget.config b/e-suite.Modules.SiteManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.SiteManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/.gitattributes b/e-suite.Modules.SpecificationManager/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/e-suite.Modules.SpecificationManager/.gitignore b/e-suite.Modules.SpecificationManager/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/e-suite.Modules.SpecificationManager/.gitignore @@ -0,0 +1,363 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/.runsettings b/e-suite.Modules.SpecificationManager/.runsettings new file mode 100644 index 0000000..e0fd691 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/README.md b/e-suite.Modules.SpecificationManager/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/azure-pipelines.yml b/e-suite.Modules.SpecificationManager/azure-pipelines.yml new file mode 100644 index 0000000..fc57c95 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/CreateSpecificationUnitTests.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/CreateSpecificationUnitTests.cs new file mode 100644 index 0000000..cb2a3bb --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/CreateSpecificationUnitTests.cs @@ -0,0 +1,143 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SpecificationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.SpecificationManager.UnitTests; + +[TestFixture] +public class CreateSpecificationUnitTests : SpecificationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void CreateSpecification_WhenSiteNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 234523, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var createSpecification = new CreateSpecification + { + Site = new GeneralIdRef() + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.CreateSpecification(auditUserDetails, createSpecification, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Site not found")); + + } + + [Test] + public void CreateSpecification_WhenFormInstanceNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 234523, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var site = new Site + { + Guid = new Guid("fbbaa30c-aaa8-4d21-8d00-898bbfdd6b74"), + Id = 235, + Name = "Bun Fight Factory" + }; + SiteManagerRepository.Sites.Add( site); + + var createSpecification = new CreateSpecification + { + Site = new GeneralIdRef + { + Guid = site.Guid + }, + FormInstanceId = new GeneralIdRef() + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.CreateSpecification(auditUserDetails, createSpecification, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Form instance not found")); + + } + + [Test] + public async Task CreateSpecification_WhenEverythingFound_CreatesSpecification() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 234523, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var site = new Site + { + Guid = new Guid("fbbaa30c-aaa8-4d21-8d00-898bbfdd6b74"), + Id = 235, + Name = "Bun Fight Factory" + }; + SiteManagerRepository.Sites.Add(site); + + var formInstance = new FormInstance + { + Guid = new Guid("cb3a91c8-9419-4815-9d52-d0f82946e5ef"), + Id = 321412433 + }; + FormRepository.FormInstances.Add(formInstance); + + var createSpecification = new CreateSpecification + { + Guid = new Guid("e2f0165d-64b0-4bf7-a06a-a9c268cbb72e"), + Name = "My new specification", + Site = new GeneralIdRef + { + Guid = site.Guid + }, + FormInstanceId = new GeneralIdRef + { + Guid = formInstance.Guid + } + }; + + //Act + await SpecificationManager.CreateSpecification(auditUserDetails, createSpecification, true, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(SpecificationManagerRepository.Specifications.Count, Is.EqualTo(1)); + var actualResult = SpecificationManagerRepository.Specifications[0]; + Assert.That(actualResult.Guid, Is.EqualTo(createSpecification.Guid)); + Assert.That(actualResult.Name, Is.EqualTo(createSpecification.Name)); + Assert.That(actualResult.Site.Guid, Is.EqualTo(site.Guid)); + Assert.That(actualResult.Site.Id, Is.EqualTo(site.Id)); + Assert.That(actualResult.FormInstanceId, Is.EqualTo(formInstance.Id)); + Assert.That(actualResult.Deleted, Is.False); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/DeleteSpecificationUnitTests.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/DeleteSpecificationUnitTests.cs new file mode 100644 index 0000000..1f22342 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/DeleteSpecificationUnitTests.cs @@ -0,0 +1,111 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SpecificationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.SpecificationManager.UnitTests; + +[TestFixture] +public class DeleteSpecificationUnitTests : SpecificationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void DeleteSpecification_WhenSpecificationNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 243623, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("611d8925-81c5-4dd4-a2b3-b12508f3d983") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.DeleteSpecification(auditUserDetails, generalIdRef, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Specification not found")); + } + + [Test] + public void DeleteSpecification_WhenSpecificationAlreadyDeleted_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 243623, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var specification = new Specification() + { + Guid = new Guid("957b578f-278a-439d-a750-818b04a13504"), + Id = 2134, + Deleted = true + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var generalIdRef = new GeneralIdRef + { + Guid = specification.Guid, + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.DeleteSpecification(auditUserDetails, generalIdRef, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Specification not found")); + } + + [Test] + public async Task DeleteSpecification_WhenSpecificationNotDeleted_DeletesSpeciciation() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 243623, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var specification = new Specification + { + Guid = new Guid("957b578f-278a-439d-a750-818b04a13504"), + Id = 2134, + Deleted = false + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var generalIdRef = new GeneralIdRef + { + Guid = specification.Guid, + }; + + //Act + await SpecificationManager.DeleteSpecification(auditUserDetails, generalIdRef, true,CancellationToken.None); + + //Assert + Assert.That(SpecificationManagerRepository.EditedSpecification, Is.Not.Null); + Assert.That(SpecificationManagerRepository.EditedSpecification, Is.EqualTo(specification)); + Assert.That(SpecificationManagerRepository.EditedSpecification!.Deleted, Is.True); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/EditSpecificationUnitTests.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/EditSpecificationUnitTests.cs new file mode 100644 index 0000000..95f7617 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/EditSpecificationUnitTests.cs @@ -0,0 +1,287 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SpecificationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Modules.SpecificationManager.UnitTests; + +[TestFixture] +public class EditSpecificationUnitTests : SpecificationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void EditSpecification_WhenSpecificationNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var edit = new EditSpecification + { + Id = new GeneralIdRef + { + Guid = new Guid("f3bdf80c-0ce7-47f9-8793-368637f88338") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.EditSpecification(auditUserDetails, edit, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Specification not found")); + } + + [Test] + public void EditSpecification_WhenSiteNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var formInstance = new FormInstance + { + Guid = new Guid("ea9f447d-4318-4a1d-8f51-fc4894392110"), + Id = 23985476 + }; + FormRepository.FormInstances.Add(formInstance); + + var site = new Site + { + Guid = new Guid("532c5a1d-78dd-42e9-9d44-2a60950d1657"), + Id = 123521345 + }; + SiteManagerRepository.Sites.Add(site); + + var specification = new Specification + { + Guid = new Guid("ff34b451-5459-4200-8e72-897e50e18a0e"), + Id = 12341, + FormInstanceId = formInstance.Id, + Site = site, + SiteId = site.Id + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var edit = new EditSpecification + { + Id = new GeneralIdRef + { + Guid = specification.Guid + }, + Site = new GeneralIdRef + { + Guid = new Guid("5c890f1b-3c2c-482f-876a-cdcb1fbbfcd7") + }, + FormInstanceId = new GeneralIdRef(){ Id = formInstance.Id }, + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.EditSpecification(auditUserDetails, edit, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Site not found")); + } + + [Test] + public void EditSpecification_WhenFormInstanceNotFound_ThrowsNotFoundException() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var specification = new Specification + { + Guid = new Guid("ff34b451-5459-4200-8e72-897e50e18a0e"), + Id = 12341 + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var site = new Site + { + Guid = new Guid("532c5a1d-78dd-42e9-9d44-2a60950d1657"), + Id = 123521345 + }; + SiteManagerRepository.Sites.Add(site); + + var edit = new EditSpecification + { + Id = new GeneralIdRef + { + Guid = specification.Guid + }, + Site = new GeneralIdRef + { + Guid = site.Guid + }, + FormInstanceId = new GeneralIdRef + { + Guid = new Guid("223584da-3303-4fc4-b72c-8ebf692e02fa") + } + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + await SpecificationManager.EditSpecification(auditUserDetails, edit, true, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Form instance not found")); + } + + [Test] + public async Task EditSpecification_WhenEverythingFound_EditsSite() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var formInstance = new FormInstance + { + Guid = new Guid("ea9f447d-4318-4a1d-8f51-fc4894392110"), + Id = 23985476 + }; + FormRepository.FormInstances.Add(formInstance); + + var site = new Site + { + Guid = new Guid("532c5a1d-78dd-42e9-9d44-2a60950d1657"), + Id = 123521345 + }; + SiteManagerRepository.Sites.Add(site); + + var specification = new Specification + { + Guid = new Guid("ff34b451-5459-4200-8e72-897e50e18a0e"), + Id = 12341, + FormInstanceId = formInstance.Id, + Site = site, + SiteId = site.Id + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var edit = new EditSpecification + { + Id = new GeneralIdRef + { + Guid = specification.Guid + }, + Site = new GeneralIdRef + { + Guid = site.Guid + }, + FormInstanceId = new GeneralIdRef + { + Guid = formInstance.Guid + } + }; + + //Act + await SpecificationManager.EditSpecification(auditUserDetails, edit, true, CancellationToken.None); + + //Assert + Assert.That(SpecificationManagerRepository.EditedSpecification, Is.Not.Null); + Assert.That(SpecificationManagerRepository.EditedSpecification!.Id, Is.EqualTo(specification.Id)); + Assert.That(SpecificationManagerRepository.EditedSpecification.Site, Is.EqualTo(site)); + Assert.That(SpecificationManagerRepository.EditedSpecification.FormInstanceId, Is.EqualTo(formInstance.Id)); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + } + + [Test] + public async Task EditSpecification_WhenSiteChanged_EditsSite() + { + //Arrange + var auditUserDetails = new AuditUserDetails + { + UserId = 2345, + UserDisplayName = "Testy McTester", + Comment = string.Empty + }; + + var formInstance = new FormInstance + { + Guid = new Guid("ea9f447d-4318-4a1d-8f51-fc4894392110"), + Id = 23985476 + }; + FormRepository.FormInstances.Add(formInstance); + + var site = new Site + { + Guid = new Guid("532c5a1d-78dd-42e9-9d44-2a60950d1657"), + Id = 123521345 + }; + SiteManagerRepository.Sites.Add(site); + + var specification = new Specification + { + Guid = new Guid("ff34b451-5459-4200-8e72-897e50e18a0e"), + Id = 12341, + FormInstanceId = formInstance.Id, + Site = site, + SiteId = site.Id + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var newSite = new Site + { + Guid = new Guid("8B8418A3-7DD0-4539-BA1A-76A8D381DA5C"), + Id = 123521346 + }; + SiteManagerRepository.Sites.Add(newSite); + + var edit = new EditSpecification + { + Id = new GeneralIdRef + { + Guid = specification.Guid + }, + Site = new GeneralIdRef + { + Guid = newSite.Guid + }, + FormInstanceId = new GeneralIdRef + { + Guid = formInstance.Guid + } + }; + + //Act + await SpecificationManager.EditSpecification(auditUserDetails, edit, true, CancellationToken.None); + + //Assert + Assert.That(SpecificationManagerRepository.EditedSpecification, Is.Not.Null); + Assert.That(SpecificationManagerRepository.EditedSpecification!.Id, Is.EqualTo(specification.Id)); + Assert.That(SpecificationManagerRepository.EditedSpecification.Site, Is.EqualTo(newSite)); + Assert.That(SpecificationManagerRepository.EditedSpecification.FormInstanceId, Is.EqualTo(formInstance.Id)); + EFlowSyncMessageSenderMock.Verify(x => x.SyncEFlowPrinterCategories(), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetSpecificationUnitTests.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetSpecificationUnitTests.cs new file mode 100644 index 0000000..42d7641 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetSpecificationUnitTests.cs @@ -0,0 +1,110 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SpecificationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.SpecificationManager.UnitTests; + +[TestFixture] +public class GetSpecificationUnitTests : SpecificationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetSpecification_WhenSpecificationMissing_ThrowsNotFoundException() + { + //Arrange + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("1326b676-e9a7-406a-a0ef-710b87290d57") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var result = await SpecificationManager.GetSpecification(generalIdRef, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Specification not found")); + } + + [Test] + public void GetSpecification_WhenSpecificationHasNoFormInstance_ReturnsNotFoundException() + { + //Arrange + var specification = new Specification + { + Guid = new Guid("1326b676-e9a7-406a-a0ef-710b87290d57") + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var generalIdRef = new GeneralIdRef + { + Guid = specification.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var result = await SpecificationManager.GetSpecification(generalIdRef, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Form instance not found")); + } + + [Test] + public async Task GetSpecification_WhenSpecificationLoadsCorrectly_ReturnsReadSpecification() + { + //Arrange + var site = new Site + { + Id = 235423, + Guid = new Guid("28df402e-5991-43d5-9342-72083f797d99"), + Name = "Room of requirement" + }; + + var formInstance = new FormInstance() + { + Id = 12354, + Guid = new Guid("1326b676-e9a7-406a-a0ef-710b87290d57") + }; + FormRepository.FormInstances.Add(formInstance); + + var specification = new Specification + { + Guid = new Guid("1326b676-e9a7-406a-a0ef-710b87290d57"), + FormInstanceId = formInstance.Id, + Name = "My Specification", + Site = site, + SiteId = site.Id + }; + SpecificationManagerRepository.Specifications.Add(specification); + + var generalIdRef = new GeneralIdRef + { + Guid = specification.Guid + }; + + //Act + var result = await SpecificationManager.GetSpecification(generalIdRef, CancellationToken.None); + + //Assert + Assert.Multiple(() => + { + Assert.That(result, Is.Not.Null); + Assert.That(result!.Guid, Is.EqualTo(specification.Guid)); + Assert.That(result.Id, Is.EqualTo(specification.Id)); + Assert.That(result.FormInstanceId.Id, Is.EqualTo(formInstance.Id)); + Assert.That(result.FormInstanceId.Guid, Is.EqualTo(formInstance.Guid)); + Assert.That(result.Name, Is.EqualTo(specification.Name)); + Assert.That(result.Site.Id, Is.EqualTo(site.Id)); + Assert.That(result.Site.Guid, Is.EqualTo(site.Guid)); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetSpecificationsUnitTests.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetSpecificationsUnitTests.cs new file mode 100644 index 0000000..e4754f5 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetSpecificationsUnitTests.cs @@ -0,0 +1,60 @@ +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Modules.SpecificationManager.UnitTests.Helpers; +using e_suite.Utilities.Pagination; +using NUnit.Framework; + +namespace e_suite.Modules.SpecificationManager.UnitTests; + +[TestFixture] +public class GetSpecificationsUnitTests : SpecificationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetSpecifications() + { + //Arrange + var paging = new Paging(); + + var formInstance = new FormInstance() + { + Guid = new Guid("43f9a0ce-cf50-4196-897d-530bc48900ed"), + Id = 2135 + }; + FormRepository.FormInstances.Add(formInstance); + + var site = new Site + { + Guid = new Guid("245f4f92-7589-472f-8d21-507335ef69e6"), + Id = 13245, + Name = "My Site" + }; + + var specification = new Specification + { + Guid = new Guid("1f3e7a69-0834-42fb-800c-ec54163d4187"), + Id = 11213, + Name = "My Example Spec", + Site = site, + SiteId = site.Id, + FormInstanceId = formInstance.Id + }; + SpecificationManagerRepository.Specifications.Add(specification); + + //Act + var result = await SpecificationManager.GetSpecifications(paging, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + + var first = result.Data.First(); + Assert.That(first.Guid, Is.EqualTo(specification.Guid)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetTemplateForPrintSpecUnitTests.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetTemplateForPrintSpecUnitTests.cs new file mode 100644 index 0000000..641223b --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/GetTemplateForPrintSpecUnitTests.cs @@ -0,0 +1,143 @@ +using System.Collections.ObjectModel; +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.Modules.SpecificationManager.UnitTests.Helpers; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; + +namespace e_suite.Modules.SpecificationManager.UnitTests; + +[TestFixture] +public class GetTemplateForPrintSpecUnitTests : SpecificationManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetTemplateForPrint_WhenGlossaryNotFound_ThrowsException() + { + //Arrange + + var generalIdRef = new GeneralIdRef + { + Guid = new Guid("0285dfde-e130-4ed2-9c6b-64b139fb6477") + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var template = await SpecificationManager.GetTemplateForPrintSpec(generalIdRef, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Template glossary item does not exist")); + } + + [Test] + public void GetTemplateForPrint_WhenGlossaryNotDefinedProperly_ThrowsException() + { + //Arrange + + var glossary = new Glossary() + { + Guid = new Guid("9929fec1-0fdb-4dd2-8a5d-4badc2e5a4b1") + }; + GlossariesManagerRepository.Glossaries.Add(glossary); + + var generalIdRef = new GeneralIdRef + { + Guid = glossary.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var template = await SpecificationManager.GetTemplateForPrintSpec(generalIdRef, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Glossary does not contain template reference")); + } + + [Test] + public void GetTemplateForPrint_WhenTemplateNotFound_ThrowsException() + { + //Arrange + var glossary = new Glossary + { + Guid = new Guid("9929fec1-0fdb-4dd2-8a5d-4badc2e5a4b1"), + CustomFieldValues = + [ + new() + { + CustomField = new CustomField + { + Guid = new Guid("{8D910089-3079-4A29-ABAD-8DDF82DB6DBB}") + }, + Value = new Guid("065b2e4d-e324-4f0d-bec0-8e3a738b8ada").ToString() + } + ] + }; + GlossariesManagerRepository.Glossaries.Add(glossary); + + var generalIdRef = new GeneralIdRef + { + Guid = glossary.Guid + }; + + //Assert + var actualResult = Assert.ThrowsAsync(async () => + { + //Act + var template = await SpecificationManager.GetTemplateForPrintSpec(generalIdRef, CancellationToken.None); + }); + Assert.That(actualResult!.Message, Is.EqualTo("Template does not exist")); + } + + [Test] + public async Task GetTemplateForPrint_WhenTemplateFound_ReturnsTemplateGeneralIdRef() + { + //Arrange + var formTemplateGuid = new Guid("ab75d0f6-f018-468b-80a4-fb696228124b"); + + var glossary = new Glossary + { + Guid = new Guid("9929fec1-0fdb-4dd2-8a5d-4badc2e5a4b1"), + CustomFieldValues = + [ + new() + { + CustomField = new CustomField + { + Guid = new Guid("{8D910089-3079-4A29-ABAD-8DDF82DB6DBB}") + }, + Value = formTemplateGuid.ToString() + } + ] + }; + GlossariesManagerRepository.Glossaries.Add(glossary); + + var formTemplate = new FormTemplate + { + Guid = formTemplateGuid, + Id = 872364 + }; + FormRepository.FormTemplates.Add(formTemplate); + + var generalIdRef = new GeneralIdRef + { + Guid = glossary.Guid + }; + + //Act + var template = await SpecificationManager.GetTemplateForPrintSpec(generalIdRef, CancellationToken.None); + + //Assert + Assert.That(template, Is.Not.Null); + Assert.That(template!.Guid, Is.EqualTo(formTemplateGuid)); + Assert.That(template.Id, Is.EqualTo(formTemplate.Id)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeFormRepository.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeFormRepository.cs new file mode 100644 index 0000000..9074e9b --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeFormRepository.cs @@ -0,0 +1,126 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.Forms; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.SpecificationManager.UnitTests.Helpers; + +public class FakeFormRepository : FakeRepository, IFormRepository +{ + public List FormTemplates { get; set; } = []; + public List FormInstances { get; set; } = []; + + public Task GetTemplateAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + return Task.FromResult(FormTemplates.FindByGeneralIdRef(id)); + } + + public Task GetTemplateWithOutLoadedRefereranceAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate template, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public IQueryable GetTemplates() + { + return FormTemplates.BuildMock(); + } + + public Task DeleteAllVersionsAsync( + AuditUserDetails auditUserDetails, + IEnumerable formTemplateVersions, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task EditFormTemplateAsync( + AuditUserDetails auditUserDetails, + FormTemplate formTemplate, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task CreateNewFormVersionAsync( + AuditUserDetails auditUserDetails, + FormTemplateVersion formTemplateVersion, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public IQueryable GetAllFormVersions(long templateId) + { + throw new NotImplementedException(); + } + + public Task GetFormTemplateVersionAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetFormTemplateWithSpecificVersionAsync( + IGeneralIdRef id, + long formTemplateVersionId, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task AddFormInstance( + AuditUserDetails auditUserDetails, + FormInstance newFormInstance, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task AddFormInstanceValues( + AuditUserDetails auditUserDetails, + List customFieldValues, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task GetFormInstance(GeneralIdRef createFormInstanceId, bool tracking, CancellationToken cancellationToken) + { + return Task.FromResult(FormInstances.FindByGeneralIdRef(createFormInstanceId)); + } + + public Task> GetFormInstances(IEnumerable generalIdRefs, bool tracking, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> GetFormsContainingFieldValue(IGeneralIdRef customFieldGeneralIdRef, string value, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task AddFormInstances(AuditUserDetails auditUserDetails, IEnumerable newFormInstance, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeGlossariesManagerRepository.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeGlossariesManagerRepository.cs new file mode 100644 index 0000000..6d5121b --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeGlossariesManagerRepository.cs @@ -0,0 +1,88 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Audit.Models; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.SpecificationManager.UnitTests.Helpers; + +public class FakeGlossariesManagerRepository : FakeRepository, IGlossariesManagerRepository +{ + public List Glossaries { get; set; } = []; + + private IQueryable GetGlossaries() + { + return Glossaries.BuildMock(); + } + + public Task AddGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossary, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossaryItem, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task FindGlossary(IGeneralIdRef glossaryItem, CancellationToken cancellationToken) + { + return Task.FromResult(GetGlossaries().FindByGeneralIdRef(glossaryItem)); + } + + public Task> FindGlossaryChildren(long parentId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> GetCustomFieldDefinitions(IEnumerable customFieldIdRefs, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetParentGlossary(IGeneralIdRef? glossaryItemParent, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public IQueryable GetGlossaryCustomFields(long glossaryId) + { + throw new NotImplementedException(); + } + + public Task SaveChildCustomFieldDefinitions( + AuditUserDetails auditUserDetails, + IReadOnlyList removalList, + IReadOnlyList additionList, + CancellationToken cancellationToken + ) + { + throw new NotImplementedException(); + } + + public Task> GetGlossaryCustomValues(IId glossary, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable items, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable> deltas, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeSiteManagerRepository.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeSiteManagerRepository.cs new file mode 100644 index 0000000..a41659a --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeSiteManagerRepository.cs @@ -0,0 +1,46 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.SpecificationManager.UnitTests.Helpers; + +public class FakeSiteManagerRepository : FakeRepository, ISiteManagerRepository +{ + public List Sites { get; set; } = []; + + public IQueryable GetSites() + { + return Sites.BuildMock(); + } + + public async Task GetSite(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await GetSites().FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public Task EditSite(AuditUserDetails auditUserDetails, Site editedSite, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateSite(AuditUserDetails auditUserDetails, Site newSite, CancellationToken cancellationToken) + { + Sites.Add(newSite); + return Task.CompletedTask; + } + + public Task CreateSite(AuditUserDetails auditUserDetails, IEnumerable newSites, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetSite(long sigmaId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeSpecificationManagerRepository.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeSpecificationManagerRepository.cs new file mode 100644 index 0000000..ae4c468 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/FakeSpecificationManagerRepository.cs @@ -0,0 +1,65 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; +using MockQueryable.Moq; + +namespace e_suite.Modules.SpecificationManager.UnitTests.Helpers; + +public class FakeSpecificationManagerRepository : FakeRepository, ISpecificationManagerRepository +{ + public List Specifications { get; set; } = []; + public Specification? EditedSpecification { get; private set; } + + public IQueryable GetSpecifications() + { + return Specifications.BuildMock(); + } + + public IQueryable GetSpecificationsFromForms(IEnumerable formIds) + { + throw new NotImplementedException(); + } + + public Task GetSpecification(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(GetSpecifications().FindByGeneralIdRef(generalIdRef)); + } + + public Task CreateSpecification( + AuditUserDetails auditUserDetails, + Specification newSpecification, + CancellationToken cancellationToken + ) + { + Specifications.Add(newSpecification); + return Task.CompletedTask; + } + + public Task EditSpecification( + AuditUserDetails auditUserDetails, + Specification specification, + CancellationToken cancellationToken + ) + { + EditedSpecification = specification; + return Task.CompletedTask; + } + + public Task CreateSpecification(AuditUserDetails auditUserDetails, IEnumerable newSpecification, CancellationToken cancellationToken) + { + Specifications.AddRange(newSpecification); + return Task.CompletedTask; + } + + public async Task EditSpecification(AuditUserDetails auditUserDetails, IEnumerable specifications, CancellationToken cancellationToken) + { + foreach (var specification in specifications) + { + await EditSpecification( auditUserDetails, specification, cancellationToken ); + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/SpecificationManagerTestBase.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/SpecificationManagerTestBase.cs new file mode 100644 index 0000000..6cb9b82 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/Helpers/SpecificationManagerTestBase.cs @@ -0,0 +1,67 @@ +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Messaging.Common; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using Moq; + +namespace e_suite.Modules.SpecificationManager.UnitTests.Helpers; + +public class SpecificationManagerTestBase : TestBase +{ + protected FakeSpecificationManagerRepository SpecificationManagerRepository { get; set; } = null!; + protected FakeGlossariesManagerRepository GlossariesManagerRepository { get; set; } = null!; + protected FakeFormRepository FormRepository { get; set; } = null!; + protected FakeSiteManagerRepository SiteManagerRepository { get; set; } = null!; + protected Mock EFlowSyncMessageSenderMock { get; set; } = null!; + + protected ISpecificationManager SpecificationManager { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + SpecificationManagerRepository = new FakeSpecificationManagerRepository(); + GlossariesManagerRepository = new FakeGlossariesManagerRepository(); + FormRepository = new FakeFormRepository(); + EFlowSyncMessageSenderMock = new Mock(); + SiteManagerRepository = new FakeSiteManagerRepository(); + + SpecificationManager = new SpecificationManager(SpecificationManagerRepository, GlossariesManagerRepository, FormRepository, SiteManagerRepository, EFlowSyncMessageSenderMock.Object); + } +} + +public class FakeDomainRepository : FakeRepository, IDomainRepository +{ + public IQueryable GetDomains() + { + throw new NotImplementedException(); + } + + public Task GetDomainById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetDomainByName(string domainName, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task AddAdministratorRoleAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/e-suite.Modules.SpecificationManager.UnitTests.csproj b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/e-suite.Modules.SpecificationManager.UnitTests.csproj new file mode 100644 index 0000000..c753d3e --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.UnitTests/e-suite.Modules.SpecificationManager.UnitTests.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + e_suite.Modules.SpecificationManager.UnitTests + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.sln b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.sln new file mode 100644 index 0000000..404d482 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.SpecificationManager", "e-suite.Modules.SpecificationManager\e-suite.Modules.SpecificationManager.csproj", "{757AFD77-D48A-4009-A749-5BD7D488B977}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{69D70469-C06E-405E-88EF-93C74E175212}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{B6752C56-50E3-4889-8C3E-1FDF40E4437A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Modules.SpecificationManager.UnitTests", "e-suite.Modules.SpecificationManager.UnitTests\e-suite.Modules.SpecificationManager.UnitTests.csproj", "{62E444E0-A80A-4D0A-9465-D7648C8639DA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {757AFD77-D48A-4009-A749-5BD7D488B977}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {757AFD77-D48A-4009-A749-5BD7D488B977}.Debug|Any CPU.Build.0 = Debug|Any CPU + {757AFD77-D48A-4009-A749-5BD7D488B977}.Release|Any CPU.ActiveCfg = Release|Any CPU + {757AFD77-D48A-4009-A749-5BD7D488B977}.Release|Any CPU.Build.0 = Release|Any CPU + {62E444E0-A80A-4D0A-9465-D7648C8639DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {62E444E0-A80A-4D0A-9465-D7648C8639DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {62E444E0-A80A-4D0A-9465-D7648C8639DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {62E444E0-A80A-4D0A-9465-D7648C8639DA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B6752C56-50E3-4889-8C3E-1FDF40E4437A} = {69D70469-C06E-405E-88EF-93C74E175212} + {62E444E0-A80A-4D0A-9465-D7648C8639DA} = {B6752C56-50E3-4889-8C3E-1FDF40E4437A} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F9FC1156-44A9-43C8-A717-3A5F5C504F97} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.v3.ncrunchsolution b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.v3.ncrunchsolution new file mode 100644 index 0000000..13107d3 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.v3.ncrunchsolution @@ -0,0 +1,8 @@ + + + True + True + True + True + + \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/GeneralIdExtensions.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/GeneralIdExtensions.cs new file mode 100644 index 0000000..536e1fb --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/GeneralIdExtensions.cs @@ -0,0 +1,13 @@ +using e_suite.Database.Core.Models; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Modules.SpecificationManager; + +public static class GeneralIdExtensions +{ + public static bool GeneralIdEquals(this IGeneralId item, IGeneralIdRef compare) + { + if (item.Id == compare.Id) return true; + return item.Guid == compare.Guid; + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/GlobalSuppressions.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/GlobalSuppressions.cs new file mode 100644 index 0000000..eadee75 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "", Scope = "member", Target = "~M:e_suite.Modules.SpecificationManager.repository.SpecificationManagerRepository.#ctor(e_suite.Database.Core.IEsuiteDatabaseDbContext)")] diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/IocRegistration.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/IocRegistration.cs new file mode 100644 index 0000000..d9d2b5b --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.SpecificationManager.repository; + +namespace e_suite.Modules.SpecificationManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/SpecificationManager.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/SpecificationManager.cs new file mode 100644 index 0000000..23609cb --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/SpecificationManager.cs @@ -0,0 +1,250 @@ + +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using System.Linq.Expressions; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using e_suite.Messaging.Common; + +namespace e_suite.Modules.SpecificationManager; + +public class SpecificationManager : ISpecificationManager +{ + private readonly ISpecificationManagerRepository _specificationManagerRepository; + private readonly IGlossariesManagerRepository _glossariesManagerRepository; + private readonly IFormRepository _formRepository; + private readonly ISiteManagerRepository _siteManagerRepository; + private readonly IEFlowSyncMessageSender _eFlowSyncMessageSender; + +#pragma warning disable IDE0290 + public SpecificationManager(ISpecificationManagerRepository specificationManagerRepository, IGlossariesManagerRepository glossariesManagerRepository, IFormRepository formRepository, ISiteManagerRepository siteManagerRepository, IEFlowSyncMessageSender eFlowSyncMessageSender) + { + _specificationManagerRepository = specificationManagerRepository; + _glossariesManagerRepository = glossariesManagerRepository; + _formRepository = formRepository; + _siteManagerRepository = siteManagerRepository; + _eFlowSyncMessageSender = eFlowSyncMessageSender; + } +#pragma warning restore IDE0290 + + private static void Assert(T? item, string message) + { + if (typeof(T).IsAssignableTo(typeof(ISoftDeletable))) + { + if (item is not ISoftDeletable deletable || deletable.Deleted) + throw new NotFoundException(message); + } + else + { + if (item == null) + throw new NotFoundException(message); + } + } + + public async Task GetTemplateForPrintSpec(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var printSpecificationTemplateGuid = new Guid("{8D910089-3079-4A29-ABAD-8DDF82DB6DBB}"); + + var printSpecification = await _glossariesManagerRepository.FindGlossary(generalIdRef, cancellationToken); + Assert(printSpecification, "Template glossary item does not exist"); + var customFieldValue = printSpecification!.CustomFieldValues.SingleOrDefault(x => x.CustomField.Guid == printSpecificationTemplateGuid); + Assert(customFieldValue, "Glossary does not contain template reference"); + var specificationFormGuid = customFieldValue!.Value; + var specificationFormGeneralIdRef = new GeneralIdRef { Guid = new Guid(specificationFormGuid) }; + var result = await _formRepository.GetTemplateAsync(specificationFormGeneralIdRef,cancellationToken); + Assert(result, "Template does not exist"); + return result.ToGeneralIdRef(); + } + + public async Task GetSpecification(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var specification = await _specificationManagerRepository.GetSpecification(generalIdRef, cancellationToken); + Assert(specification, "Specification not found"); + return await MapSpecification(specification!, cancellationToken); + } + + private readonly Dictionary _siteDictionary = []; + + public async Task CreateSpecification( + AuditUserDetails auditUserDetails, + CreateSpecification create, + bool triggerEFlowSync, + CancellationToken cancellationToken + ) + { + await CreateSpecification(auditUserDetails, [create], triggerEFlowSync, cancellationToken); + } + + public async Task CreateSpecification( + AuditUserDetails auditUserDetails, + IEnumerable items, + bool triggerEFlowSync, + CancellationToken cancellationToken + ) + { + var newSpecifications = new List(); + foreach (var create in items) + { + if (!_siteDictionary.TryGetValue(create.Site, out var site)) + { + site = await _siteManagerRepository.GetSite(create.Site, cancellationToken) ?? + throw new NotFoundException("Site not found"); + _siteDictionary.Add(create.Site, site); + } + + var formInstance = await _formRepository.GetFormInstance(create.FormInstanceId, false, cancellationToken) ?? + throw new NotFoundException("Form instance not found"); + + var newSpecification = new Specification + { + Guid = create.Guid ?? Guid.NewGuid(), + Name = create.Name, + FormInstanceId = formInstance.Id, + Site = site, + SiteId = site.Id, + SigmaId = create.SigmaId + }; + + newSpecifications.Add(newSpecification); + } + + await _specificationManagerRepository.TransactionAsync(async () => + { + await _specificationManagerRepository.CreateSpecification(auditUserDetails, newSpecifications, cancellationToken); + }); + + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + } + + public async Task> GetSpecifications(Paging paging, CancellationToken cancellationToken) + { + var specifications = _specificationManagerRepository.GetSpecifications(); + + var paginatedData = await PaginatedData.Paginate(specifications, paging, + KeySelector, FilterSelector, cancellationToken); + + var dataPage = new List(); + foreach (var data in paginatedData.Data) + dataPage.Add(await MapSpecification(data, cancellationToken)); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = dataPage + }; + + + return paginatedResult; + } + + private async Task MapSpecification(Specification specification, CancellationToken cancellationToken) + { + var formInstanceId = specification.FormInstanceId; + + var formInstance = await _formRepository.GetFormInstance(new GeneralIdRef { Id = formInstanceId }, false, cancellationToken) ?? + throw new NotFoundException("Form instance not found"); + + return new ReadSpecification + { + Id = specification.Id, + Guid = specification.Guid, + Name = specification.Name, + Site = specification.Site.ToGeneralIdRef()!, + SigmaId = specification.SigmaId, + FormInstanceId = formInstance.ToGeneralIdRef()!, + }; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + "guid" => x => x.Guid.ToString().Contains(value), + "name" => x => x.Name.Contains(value), + "site.id" => x => x.Site.Id == long.Parse(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "id" => x => x.Id, + "guid" => x => x.Guid, + "name" => x => x.Name, + "site.id" => x => x.Site.Id, + _ => x => x.Name + }; + } + + public async Task DeleteSpecification( + AuditUserDetails auditUserDetails, + GeneralIdRef generalIdRef, + bool triggerEFlowSync, + CancellationToken cancellationToken + ) + { + await _specificationManagerRepository.TransactionAsync(async () => + { + var specification = await _specificationManagerRepository.GetSpecification(generalIdRef, cancellationToken); + Assert(specification, "Specification not found"); + + specification!.Deleted = true; + await _specificationManagerRepository.EditSpecification(auditUserDetails, specification, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + }); + } + + public async Task EditSpecification(AuditUserDetails auditUserDetails, EditSpecification edit, bool triggerEFlowSync, CancellationToken cancellationToken) + { + await EditSpecification(auditUserDetails, [edit], triggerEFlowSync, cancellationToken); + } + + public async Task EditSpecification(AuditUserDetails auditUserDetails, IEnumerable items, bool triggerEFlowSync, CancellationToken cancellationToken) + { + await _specificationManagerRepository.TransactionAsync(async () => + { + var updates = new List(); + foreach (var edit in items) + { + var specification = + await _specificationManagerRepository.GetSpecification(edit.Id, cancellationToken) ?? + throw new NotFoundException("Specification not found"); + + var formInstance = await _formRepository.GetFormInstance(edit.FormInstanceId, false, cancellationToken) ?? + throw new NotFoundException("Form instance not found"); + + specification.Name = edit.Name; + specification.FormInstanceId = formInstance.Id; + + if (!specification.Site.GeneralIdEquals(edit.Site)) + { + var site = await _siteManagerRepository.GetSite(edit.Site, cancellationToken) ?? + throw new NotFoundException("Site not found"); + specification.Site = site; + specification.SiteId = site.Id; + } + + //todo sort out the domain delta changes here. + + updates.Add(specification); + } + + await _specificationManagerRepository.EditSpecification(auditUserDetails, updates, cancellationToken); + if (triggerEFlowSync) + _eFlowSyncMessageSender.SyncEFlowPrinterCategories(); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.csproj b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.csproj new file mode 100644 index 0000000..e41a995 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Modules.SpecificationManager + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/repository/SpecificationManagerRepository.cs b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/repository/SpecificationManagerRepository.cs new file mode 100644 index 0000000..376e720 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/e-suite.Modules.SpecificationManager/repository/SpecificationManagerRepository.cs @@ -0,0 +1,77 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Printer; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Modules.SpecificationManager.repository; + +public class SpecificationManagerRepository : RepositoryBase, ISpecificationManagerRepository +{ + public SpecificationManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public IQueryable GetSpecifications() + { + return DatabaseDbContext.Specifications + .Include(x => x.Site) + .ThenInclude( x => x.Organisation) + .Where(x => x.Deleted == false); + } + + public IQueryable GetSpecificationsFromForms(IEnumerable formIds) + { + var specifications = GetSpecifications() + .Where(x => formIds.Contains(x.Id)); + + return specifications; + } + + public async Task GetSpecification(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await GetSpecifications().FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task CreateSpecification( + AuditUserDetails auditUserDetails, + Specification newSpecification, + CancellationToken cancellationToken + ) + { + DatabaseDbContext.Specifications.Add(newSpecification); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task CreateSpecification( + AuditUserDetails auditUserDetails, + IEnumerable newSpecifications, + CancellationToken cancellationToken + ) + { + await DatabaseDbContext.Specifications.AddRangeAsync(newSpecifications, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditSpecification( + AuditUserDetails auditUserDetails, + Specification specification, + CancellationToken cancellationToken + ) + { + DatabaseDbContext.Specifications.Update(specification); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditSpecification( + AuditUserDetails auditUserDetails, + IEnumerable specifications, + CancellationToken cancellationToken + ) + { + DatabaseDbContext.Specifications.UpdateRange(specifications); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Modules.SpecificationManager/nuget.config b/e-suite.Modules.SpecificationManager/nuget.config new file mode 100644 index 0000000..cbf30a9 --- /dev/null +++ b/e-suite.Modules.SpecificationManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.UserManager/.gitattributes b/e-suite.Modules.UserManager/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Modules.UserManager/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Modules.UserManager/.gitignore b/e-suite.Modules.UserManager/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Modules.UserManager/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Modules.UserManager/.runsettings b/e-suite.Modules.UserManager/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Modules.UserManager/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Modules.UserManager/README.md b/e-suite.Modules.UserManager/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Modules.UserManager/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/Helpers/UserManagerMaintenanceTestBase.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/Helpers/UserManagerMaintenanceTestBase.cs new file mode 100644 index 0000000..96a190c --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/Helpers/UserManagerMaintenanceTestBase.cs @@ -0,0 +1,20 @@ +using e_suite.API.Common; +using e_suite.UnitTestCore; +using UserManager.UnitTests.Repository; + +namespace UserManager.UnitTests.Helpers; + +public class UserManagerMaintenanceTestBase : TestBase +{ + protected FakeUserManagerRepository UserManagerRepository { get; set; } = null!; + protected IUserManagerMaintenance UserManagerManagerMaintenance { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + UserManagerRepository = new FakeUserManagerRepository(_fakeClock); + + UserManagerManagerMaintenance = new e_suite.Modules.UserManager.UserManagerMaintenance(UserManagerRepository); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/Helpers/UserManagerTestBase.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/Helpers/UserManagerTestBase.cs new file mode 100644 index 0000000..085edf7 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/Helpers/UserManagerTestBase.cs @@ -0,0 +1,59 @@ +using e_suite.API.Common; +using e_suite.Database.Audit; +using e_suite.Modules.UserManager.Facade; +using e_suite.Modules.UserManager.Services; +using e_suite.Nuget.PasswordHasher; +using e_suite.UnitTestCore; +using eSuite.Core.MailService; +using Google.Authenticator; +using Microsoft.AspNetCore.Identity; +using Moq; +using UserManager.UnitTests.Repository; + +namespace UserManager.UnitTests.Helpers; + +public class UserManagerTestBase : TestBase +{ + protected Mock> CustomPasswordHasherMock = null!; + protected Mock TwoFactorAuthenticatorMock = null!; + protected Mock JwtServiceMock = null!; + protected Mock MailServiceMock = null!; + protected Mock RandomNumberGeneratorMock = null!; + protected FakeUserManagerRepository UserManagerRepository = null!; + protected FakeDomainRepository DomainRepository = null!; + + protected AuditUserDetails AuditUserDetails = null!; + protected SetupCode SetupCode = null!; + + protected IUserManager UserManager = null!; + + public override async Task Setup() + { + await base.Setup(); + + AuditUserDetails = new AuditUserDetails + { + UserId = -1, + UserDisplayName = "Testing User", + Comment = "Test comment" + }; + + JwtServiceMock = new Mock(); + CustomPasswordHasherMock = new Mock>(); + TwoFactorAuthenticatorMock = new Mock(); + + SetupCode = new SetupCode(); + + TwoFactorAuthenticatorMock.Setup( + x => x.GenerateSetupCode(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())).Returns(SetupCode); + + MailServiceMock = new Mock(); + RandomNumberGeneratorMock = new Mock(); + UserManagerRepository = new FakeUserManagerRepository(_fakeClock); + DomainRepository = new FakeDomainRepository(); + + UserManager = new e_suite.Modules.UserManager.UserManager(_configuration, CustomPasswordHasherMock.Object, + TwoFactorAuthenticatorMock.Object, JwtServiceMock.Object, MailServiceMock.Object, RandomNumberGeneratorMock.Object, _fakeClock, UserManagerRepository, DomainRepository); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/Repository/FakeDomainRepository.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/Repository/FakeDomainRepository.cs new file mode 100644 index 0000000..d0d9897 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/Repository/FakeDomainRepository.cs @@ -0,0 +1,44 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace UserManager.UnitTests.Repository; + +public class FakeDomainRepository : FakeRepository, IDomainRepository +{ + public List Domains = []; + + public IQueryable GetDomains() + { + return Domains.BuildMock(); + } + + public Task GetDomainById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(GetDomains().FindByGeneralIdRef(generalIdRef)); + } + + public Task GetDomainByName(string domainName, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateDomainAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task AddAdministratorRoleAsync(AuditUserDetails auditUserDetails, Domain domain, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/Repository/FakeUserManagerRepository.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/Repository/FakeUserManagerRepository.cs new file mode 100644 index 0000000..4157f57 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/Repository/FakeUserManagerRepository.cs @@ -0,0 +1,233 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.UnitTestCore; +using eSuite.Core.Clock; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using MockQueryable; + +namespace UserManager.UnitTests.Repository; + +public class FakeUserManagerRepository : FakeRepository, IUserManagerRepository +{ + private readonly IClock _clock; + + public List Users = []; + public List EmailUserActions = []; + public List Domains = []; + public List SsoProviders = []; + public List SingleUseGuids = []; + + public FakeUserManagerRepository(IClock clock) + { + _clock = clock; + + Domains.Add( new Domain + { + Id = 1, + Guid = new Guid("{E5B6C043-C2EB-46CC-9387-E5F45420C93F}"), + Name = "Default Test domain" + } + ); + + Domains.Add(new Domain + { + Id = 2, + Guid = new Guid("d3d36362-dd2a-490a-b8ef-71ee59934b8d"), + Name = "Alternative Test Domain" + } + ); + + SsoProviders.Add(new SsoProvider + { + Id = 1, + Name = "Test provider", + ClientId = "SecretClientId", + ClientSecret = "NotTellingYou", + Deleted = false, + IsPublic = true, + AuthorizationEndpoint = "AuthorizationEndpoint", + TokenEndpoint = "TokenEndpoint", + ValidIssuer = "ValidIssuer" + }); + + Users.Add( new User + { + Id = -1, + Guid = new Guid("{EA6A2EB2-ADBF-47A1-8FA6-EF363D0750DC}"), + Email = "audit@test.test", + FirstName = "Audit", + LastName = "Tester", + DomainId = Domains[0].Id, + Domain = Domains[0], + EmailConfirmed = true, + Created = new DateTimeOffset(2023, 7, 24, 13, 45, 24, TimeSpan.Zero), + LastUpdated = new DateTimeOffset(2023, 7, 24, 13, 45, 25, TimeSpan.Zero) + }); + } + + public Task GetUserByEmail(string loginEmail, CancellationToken cancellationToken) + { + //return Task.FromResult(Users.SingleOrDefault(x => x.Email.Equals(loginEmail, StringComparison.InvariantCultureIgnoreCase))); + return Task.FromResult(Users.SingleOrDefault(x => x.Email.Equals(loginEmail, StringComparison.InvariantCultureIgnoreCase))); + } + + public async Task GetUserSsoId(long ssoId, string ssoUserId, CancellationToken cancellationToken) + { + var users = await GetUsers() + .Where(u => u.SsoProviderId.Equals(ssoId) && u.SsoSubject.Equals(ssoUserId)) + .ToListAsync(cancellationToken); + return users.FirstOrDefault(); + } + + public async Task GetUserByDomainSsoId(long domainSsoId, string ssoUserId, CancellationToken cancellationToken) + { + var users = await GetUsers() + .Where(u => u.Domain.SsoProviderId.Equals(domainSsoId) && u.SsoSubject.Equals(ssoUserId)) + .ToListAsync(cancellationToken); + return users.FirstOrDefault(); + } + + public Task AddEmailUserAction(AuditUserDetails auditUserDetails, EmailUserAction emailConfirmation, + CancellationToken cancellationToken) + { + emailConfirmation.User = Users.Single(x => x.Id == emailConfirmation.UserId); + EmailUserActions.Add(emailConfirmation); + return Task.CompletedTask; + } + + public Task AddUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + if (Users.Any(x => x.Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase))) + throw new Exception("User already exists"); + + Users.Add(user); + return Task.CompletedTask; + } + + public Task EditUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + var realUser = Users.Single(x => x.Id == user.Id); + + realUser.FirstName = user.FirstName; + realUser.LastName = user.LastName; + realUser.MiddleNames = user.MiddleNames; + realUser.Email = user.Email; + realUser.Password = user.Password; + realUser.EmailConfirmed = user.EmailConfirmed; + realUser.UsingTwoFactorAuthentication = user.UsingTwoFactorAuthentication; + realUser.TwoFactorAuthenticationKey = user.TwoFactorAuthenticationKey; + realUser.Created = user.Created; + realUser.Active = user.Active; + realUser.LastUpdated = _clock.GetNow; + return Task.CompletedTask; + } + + public Task GetEmailUserAction(Guid token, CancellationToken cancellationToken) + { + return Task.FromResult(EmailUserActions.SingleOrDefault(c => c.Token.Equals(token) + && c.Expires > _clock.GetNow)); + } + + public Task DeleteEmailUserAction(AuditUserDetails auditUserDetails, EmailUserAction emailUserAction, CancellationToken cancellationToken) + { + var item = EmailUserActions.Single(x => x.Token.Equals(emailUserAction.Token)); + EmailUserActions.Remove(item); + return Task.CompletedTask; + } + + public IQueryable GetUsers() + { + return Users.BuildMock(); + } + + public Task GetUserById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return Task.FromResult(Users.SingleOrDefault(x => x.Id == generalIdRef.Id || x.Guid == generalIdRef.Guid )); + } + + public Task GetSsoProviderById(long id, CancellationToken cancellationToken) + { + return Task.FromResult(SsoProviders.SingleOrDefault(x => x.Id == id)); + } + + public IQueryable GetSsoProviders() + { + return SsoProviders.BuildMock(); + } + + public Task SaveSingleUseGuidForUser(SingleUseGuid singleUseGuid, CancellationToken cancellationToken) + { + SingleUseGuids.Add(singleUseGuid); + return Task.CompletedTask; + } + + public Task GetUserBySingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + var singleUserGuid = SingleUseGuids.SingleOrDefault(x => x.Guid == guid && x.Expires >= _clock.GetNow); + return Task.FromResult(singleUserGuid?.User); + } + + public Task DeleteSingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + var singleUserGuid = SingleUseGuids.SingleOrDefault(x => x.Guid == guid && x.Expires >= _clock.GetNow); + + if (singleUserGuid != null) + { + SingleUseGuids.Remove(singleUserGuid); + } + return Task.CompletedTask; + } + + public Task GetUserById(GeneralIdRef generalIdRef) + { + foreach (var user in Users) + { + if (user.Id == generalIdRef.Id) + return Task.FromResult(user)!; + + if (user.Guid == generalIdRef.Guid) + return Task.FromResult(user)!; + } + + return Task.FromResult(null); + } + + public Task GetDomainById(GeneralIdRef domainId, CancellationToken cancellationToken) + { + return Task.FromResult(Domains.FindByGeneralIdRef(domainId)); + } + + public Task DeleteExpiredEmailUserActions() + { + DeleteExpiredEmailUserActionsCalled = true; + return Task.CompletedTask; + } + + public Task DeleteExpiredSingleUseGuids() + { + DeleteExpiredSingleUseGuidsCalled = true; + return Task.CompletedTask; + + } + public bool DeleteExpiredSingleUseGuidsCalled { get; set; } + + public Task GetCurrentEmailUserAction(long userId, EmailUserActionType emailUserActionType, CancellationToken cancellationToken) + { + var now = _clock.GetNow; + var result = EmailUserActions.Where( + x => x.UserId == userId + && x.EmailActionType == emailUserActionType + && x.Expires > now) + .OrderByDescending(x => x.Expires) + .FirstOrDefault(); + + return Task.FromResult(result); + } + + public bool DeleteExpiredEmailUserActionsCalled { get; set; } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager.UnitTests.csproj b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager.UnitTests.csproj new file mode 100644 index 0000000..74bf6ab --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CompleteEmailActionUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CompleteEmailActionUnitTests.cs new file mode 100644 index 0000000..1e5bc80 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CompleteEmailActionUnitTests.cs @@ -0,0 +1,598 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.MailService; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class CompleteEmailActionUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public Task CompleteEmailAction_TokenNotFound_ThrowsTokenInvalidException() + { + //Arrange + var token = new EmailActionToken + { + Email = "evil.hacker@sun-strategy.com", + Token = new Guid("{84CC5C02-0A14-465B-AB14-6D5125D50E7B}") + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.CompleteEmailAction(token); + }); + return Task.CompletedTask; + } + + [Test] + public async Task CompleteEmailAction_TokenOutOfDate_ThrowsTokenInvalidException() + { + //Arrange + var actualUser = new User + { + Id = 1, + Email = "testuser@sun-strategy.com" + }; + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{F5035CA7-E2B1-46B3-8E1A-B121107E66AD}") + }; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.ConfirmEmailAddress, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 06, 11, 43, 0, TimeSpan.Zero); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.CompleteEmailAction(token); + }); + } + + [Test] + public async Task CompleteEmailAction_UserEmailDoesNotMatchTheToken_ThrowsInvalidEmailException() + { + //Arrange + var actualUser = new User + { + Id = 2, + Email = "testuser@sun-strategy.com" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.ConfirmEmailAddress, + Token = new Guid("{632B559B-4641-4973-A1C0-38D198816201}"), + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + var token = new EmailActionToken + { + Email = "evil.hacker@sun-strategy.com", + Token = emailUserAction.Token, + Password = "P@ssword12345" + }; + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.CompleteEmailAction(token); + }); + } + + [Test] + public async Task CompleteEmailAction_ConfirmEmail_CompletedSuccessfully() + { + //Arrange + var actualUser = new User + { + Id = 3, + Email = "testuser2@sun-strategy.com", + EmailConfirmed = false, + Password = "aA1!12345789" + }; + + var oldPassword = actualUser.Password; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = "testuser2@sun-strategy.com", + Token = new Guid("{9275C68F-A88A-4AD5-963B-64678E3ABFF9}"), + Password = "Pa55W0rD-3d1ce44c-86ce-4136!b6ad-8b24303e1cfc" + }; + + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.ConfirmEmailAddress, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + //Act + var exception = Assert.ThrowsAsync(async () => + { + await UserManager.CompleteEmailAction(token); + }); + + //Assert + Assert.That(exception!.Message, Is.EqualTo($"EmailActionType {emailUserAction.EmailActionType} not supported, use the UI instead.")); + } + + [Test] + public async Task CompleteEmailAction_ResetPasswordNewPasswordMissing_ThrowsException() + { + //Arrange + var actualUser = new User + { + Id = 4, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I don't know aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + var exception = Assert.ThrowsAsync(async () => await UserManager.CompleteEmailAction(token)); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"Password must be at least 12 characters")); + } + + [Test] + public async Task CompleteEmailAction_ResetPasswordNewPasswordIsTooShort_ThrowsException() + { + //Arrange + var actualUser = new User + { + Id = 4, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I don't know aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + Password = "test" + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + var exception = Assert.ThrowsAsync(async () => await UserManager.CompleteEmailAction(token)); + + //Assert + Assert.That(exception?.Message, Is.EqualTo("Password must be at least 12 characters")); + } + + [Test] + public async Task CompleteEmailAction_ResetPasswordDoesNotContainAValidSymbol_ThrowsException() + { + //Arrange + var actualUser = new User + { + Id = 4, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I don't know aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + Password = "testtesttest" + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + var exception = Assert.ThrowsAsync(async () => await UserManager.CompleteEmailAction(token)); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"Password must contain at least one symbol: ~`! @#$%^&*()_+={{[}}|\\:;\"'<,->.?/")); + } + + [TestCase('~')] + [TestCase('`')] + [TestCase('!')] + [TestCase(' ')] + [TestCase('@')] + [TestCase('#')] + [TestCase('$')] + [TestCase('%')] + [TestCase('^')] + [TestCase('&')] + [TestCase('(')] + [TestCase(')')] + [TestCase('_')] + [TestCase('+')] + [TestCase('=')] + [TestCase('{')] + [TestCase('[')] + [TestCase('}')] + [TestCase('|')] + [TestCase('\\')] + [TestCase(':')] + [TestCase(';')] + [TestCase('\"')] + [TestCase('\'')] + [TestCase('<')] + [TestCase(',')] + [TestCase('-')] + [TestCase('>')] + [TestCase('.')] + [TestCase('?')] + [TestCase('/')] + [TestCase('"')] + public async Task CompleteEmailAction_ResetPasswordDoesNotContainAValidNumber_ThrowsException(char symbol) + { + //Arrange + var actualUser = new User + { + Id = 4, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I don't know aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + Password = $"t{symbol}sttesttest" + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + var exception = Assert.ThrowsAsync(async () => await UserManager.CompleteEmailAction(token)); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"Password must contain at least one number")); + } + + [TestCase('0')] + [TestCase('1')] + [TestCase('2')] + [TestCase('3')] + [TestCase('4')] + [TestCase('5')] + [TestCase('6')] + [TestCase('7')] + [TestCase('8')] + [TestCase('9')] + public async Task CompleteEmailAction_ResetPasswordDoesNotContainAUpperCaseCharacter_ThrowsException(char number) + { + //Arrange + var actualUser = new User + { + Id = 4, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I don't know aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + Password = $"t*{number}ttesttest" + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + var exception = Assert.ThrowsAsync(async () => await UserManager.CompleteEmailAction(token)); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"Password must contain at least one upper case character")); + } + + [Test] + public async Task CompleteEmailAction_ResetPasswordDoesNotContainALowerCaseCharacter_ThrowsException() + { + //Arrange + var actualUser = new User + { + Id = 4, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I don't know aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + Password = $"T*1TTESTTEST" + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + var exception = Assert.ThrowsAsync(async () => await UserManager.CompleteEmailAction(token)); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"Password must contain at least one lower case character")); + } + + [Test] + public async Task CompleteEmailAction_ResetPassword_CompletedSuccessfully() + { + //Arrange + var actualUser = new User + { + Id = 5, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Password = "I've forgotten aA1!12345789" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = new Guid("{CAA1C1E2-7876-4ACB-A050-8CF94466CC4E}"), + Password = "Pa55W0rD-3d1ce44c-86ce-4136-b6ad-8b24303e1cfc" + }; + + var oldPassword = actualUser.Password; + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.PasswordReset, + Token = token.Token, + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + await UserManager.CompleteEmailAction(token); + + //Assert + var databaseRow = UserManagerRepository.EmailUserActions.SingleOrDefault(x => x.Token == token.Token); + Assert.That(databaseRow, Is.Null); + + var user = UserManagerRepository.Users.Single(x => x.Email == token.Email); + Assert.That(user.Password, Is.Not.EqualTo(oldPassword)); + Assert.That(user.Password, Is.EqualTo(hashedPassword)); + + MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task CompleteEmailAction_DisableTwoFactorAuthentivation_CompletedSuccessfully() + { + //Arrange + var actualUser = new User + { + Id = 6, + Email = "testuser3@sun-strategy.com", + EmailConfirmed = false, + Password = "I've forgotten aA1!12345789", + UsingTwoFactorAuthentication = true + }; + + await UserManagerRepository.AddUser(AuditUserDetails, actualUser, default); + + var emailUserAction = new EmailUserAction + { + EmailActionType = EmailUserActionType.DisableAuthenticator, + Token = new Guid("{9B44A60C-AB66-4161-BF17-EEAC2162EAC2}"), + User = actualUser, + UserId = actualUser.Id, + Created = new DateTimeOffset(2022, 08, 03, 11, 43, 0, TimeSpan.Zero), + Expires = new DateTimeOffset(2022, 08, 05, 11, 43, 0, TimeSpan.Zero), + }; + + await UserManagerRepository.AddEmailUserAction(AuditUserDetails, emailUserAction, default); + + var token = new EmailActionToken + { + Email = actualUser.Email, + Token = emailUserAction.Token + }; + + + _fakeClock.DateTime = new DateTimeOffset(2022, 08, 04, 11, 43, 0, TimeSpan.Zero); + + //Act + await UserManager.CompleteEmailAction(token); + + //Assert + var databaseRow = UserManagerRepository.EmailUserActions.SingleOrDefault(x => x.Token == token.Token); + Assert.That(databaseRow, Is.Null); + + var user = UserManagerRepository.Users.Single(x => x.Email == token.Email); + Assert.That(user.UsingTwoFactorAuthentication, Is.False); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CreateSingleUseGuidUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CreateSingleUseGuidUnitTests.cs new file mode 100644 index 0000000..9e9473a --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CreateSingleUseGuidUnitTests.cs @@ -0,0 +1,54 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class CreateSingleUseGuidUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task CreateSingleUseGuid_UserExists_TurnsOffSsoForUser() + { + //Arrange + var user = new User + { + Id = 2, + Email = "testuser@sun-strategy.com" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + //Act + var guid = await UserManager.CreateSingleUseGuid(AuditUserDetails, user.ToGeneralIdRef()!, CancellationToken.None); + + //Assert + Assert.That(guid, Is.Not.Null); + } + + [Test] + public void CreateSingleUseGuid_UserDoesNotExist_ThrowsNotFoundException() + { + //Arrange + var user = new User + { + Id = 2, + Email = "testuser@sun-strategy.com", + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + var guid = await UserManager.CreateSingleUseGuid(AuditUserDetails, user.ToGeneralIdRef()!, + CancellationToken.None); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CreateUserUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CreateUserUnitTests.cs new file mode 100644 index 0000000..7a96675 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/CreateUserUnitTests.cs @@ -0,0 +1,270 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class CreateUserUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + /// + /// Cannot create the same user twice. + /// + [Test] + public async Task CreateUser_UserExists_ThrowException() + { + //Arrange + var existingUser = new User + { + Id = 6, + Email = "testuser@sun-strategy.com", + FirstName = "Test", + LastName = "User" + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var userRegistration = new UserRegistration + { + Email = "testuser@sun-strategy.com", + FirstName = "Test", + LastName = "User" + }; + + //Act & Assert + Assert.ThrowsAsync(() => UserManager.CreateUser(AuditUserDetails, userRegistration)); + } + + /// + /// Can create a user that does not already exist + /// + /// + [Test] + public async Task CreateUser_DoesNotExist_CreatesUser() + { + //Arrange + var userRegistration = new UserRegistration + { + Email = "testuser10@sun-strategy.com", + FirstName = "Test1", + LastName = "User" + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Act + await UserManager.CreateUser(AuditUserDetails, userRegistration); + + //Assert + RandomNumberGeneratorMock.Verify(x => x.GetRandomString(It.IsAny()), Times.Exactly(2)); //one for the tfa, and one for the default password. + + //Assert that the user was added to the database + var databaseRowToCheck = UserManagerRepository.Users.SingleOrDefault(x => x.Email == userRegistration.Email); + + Assert.That(databaseRowToCheck, Is.Not.Null); //Check row added to database + Assert.That(databaseRowToCheck?.Password, Is.EqualTo(hashedPassword)); //User has hashed password + Assert.That(databaseRowToCheck?.UsingTwoFactorAuthentication, Is.False); //UsingTwoFactorAuthentication disabled + + //Assert that the e-mail request was logged properly + var emailUserAction = UserManagerRepository.EmailUserActions.Single(x => x.User.Email == userRegistration.Email); + + Assert.That(emailUserAction, Is.Not.Null); + Assert.That(emailUserAction?.EmailActionType, Is.EqualTo(EmailUserActionType.ConfirmEmailAddress)); + Assert.That(emailUserAction?.User.Email, Is.EqualTo(userRegistration.Email)); + Assert.That(emailUserAction?.Token, Is.Not.Empty); + + //Assert that the e-mail request was sent. + MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(actualMailRequest, Is.Not.Null); + Assert.That(actualMailRequest.EmailType, Is.EqualTo(MailType.ConfirmEmailAddress)); + Assert.That(actualMailRequest.To.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.To[0].DisplayName, Is.EqualTo(userRegistration.FirstName + " " + userRegistration.LastName)); + Assert.That(actualMailRequest.To[0].Email, Is.EqualTo(userRegistration.Email.Trim())); + Assert.That(actualMailRequest.Parameters.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.Parameters["url"], Is.Not.Empty); + } + + + /// + /// Can create a user that does not already exist + /// + /// + [Test] + public void CreateUser_NonExistingDomainIdSupplied_ThrowsNotFoundException() + { + //Arrange + var userRegistration = new UserRegistration + { + Email = "testuser10@sun-strategy.com", + FirstName = "Test1", + LastName = "User", + DomainId = new GeneralIdRef { Guid = new Guid("3b3be044-f55e-4608-ab20-2b5fd4be450f") } + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await UserManager.CreateUser(AuditUserDetails, userRegistration); + }); + } + + /// + /// Can create a user that does not already exist + /// + /// + [Test] + public async Task CreateUser_GivingADomainId_CreatesUser() + { + //Arrange + var userRegistration = new UserRegistration + { + Email = "testuser10@sun-strategy.com", + FirstName = "Test1", + LastName = "User", + DomainId = new GeneralIdRef { Guid = new Guid("d3d36362-dd2a-490a-b8ef-71ee59934b8d") } + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Act + await UserManager.CreateUser(AuditUserDetails, userRegistration); + + //Assert + RandomNumberGeneratorMock.Verify(x => x.GetRandomString(It.IsAny()), Times.Exactly(2)); //one for the tfa, and one for the default password. + + //Assert that the user was added to the database + var databaseRowToCheck = UserManagerRepository.Users.SingleOrDefault(x => x.Email == userRegistration.Email); + + Assert.That(databaseRowToCheck, Is.Not.Null); //Check row added to database + Assert.That(databaseRowToCheck?.Password, Is.EqualTo(hashedPassword)); //User has hashed password + Assert.That(databaseRowToCheck?.UsingTwoFactorAuthentication, Is.False); //UsingTwoFactorAuthentication disabled + + //Assert that the e-mail request was logged properly + var emailUserAction = UserManagerRepository.EmailUserActions.Single(x => x.User.Email == userRegistration.Email); + + Assert.That(emailUserAction, Is.Not.Null); + Assert.That(emailUserAction?.EmailActionType, Is.EqualTo(EmailUserActionType.ConfirmEmailAddress)); + Assert.That(emailUserAction?.User.Email, Is.EqualTo(userRegistration.Email)); + Assert.That(emailUserAction?.Token, Is.Not.Empty); + + //Assert that the e-mail request was sent. + MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(actualMailRequest, Is.Not.Null); + Assert.That(actualMailRequest.EmailType, Is.EqualTo(MailType.ConfirmEmailAddress)); + Assert.That(actualMailRequest.To.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.To[0].DisplayName, Is.EqualTo(userRegistration.FirstName + " " + userRegistration.LastName)); + Assert.That(actualMailRequest.To[0].Email, Is.EqualTo(userRegistration.Email.Trim())); + Assert.That(actualMailRequest.Parameters.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.Parameters["url"], Is.Not.Empty); + } + + /// + /// They need to have a valid e-mail to be created. + /// + [TestCase("testuser1@sun-s@trategy.com")] + [TestCase("test@user1@sun-strategy.com ")] + [TestCase(" sun-strategy.com")] + public Task CreateUser_InvalidEmail_Throws(string email) + { + //Arrange + var userRegistration = new UserRegistration + { + Email = email + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.CreateUser(AuditUserDetails, userRegistration); + }); + return Task.CompletedTask; + } + + + + /// + /// Can reactivate a deactivated user + /// + /// + [Test] + public async Task CreateUser_ExistsButDeactivated_UserIsReactivated() + { + //Arrange + + var existingUser = new User + { + Id = 6, + Email = "testuser@sun-strategy.com", + FirstName = "Test", + LastName = "User", + Active = false + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var userRegistration = new UserRegistration + { + Email = "testuser0@sun-strategy.com", + FirstName = "Test1", + LastName = "User1" + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Act + await UserManager.CreateUser(AuditUserDetails, userRegistration); + + //Assert + RandomNumberGeneratorMock.Verify(x => x.GetRandomString(It.IsAny()), Times.Exactly(2)); //one for the tfa, and one for the default password. + + //Assert that the user was added to the database + var databaseRowToCheck = UserManagerRepository.Users.SingleOrDefault(x => x.Email == userRegistration.Email); + + Assert.That(databaseRowToCheck, Is.Not.Null); //Check row added to database + Assert.That(databaseRowToCheck?.Active, Is.True); //UsingTwoFactorAuthentication disabled + + Assert.That(databaseRowToCheck?.FirstName, Is.EqualTo("Test1")); //UsingTwoFactorAuthentication disabled + Assert.That(databaseRowToCheck?.LastName, Is.EqualTo("User1")); //UsingTwoFactorAuthentication disabled + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/DeactivateUserUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/DeactivateUserUnitTests.cs new file mode 100644 index 0000000..f589d1f --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/DeactivateUserUnitTests.cs @@ -0,0 +1,163 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class DeactivateUserUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task DeactivateUser_ActiveUser_DeactivatesUser() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "deactivate.me@sun-strategy.com", + Active = true, + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + await UserManager.DeactivateUser(AuditUserDetails, existingUser.Email); + + //Assert + var user = UserManagerRepository.Users.Single(x => x.Email == existingUser.Email); + Assert.That(user.Active, Is.False); + } + + [Test] + public async Task DeactivateUser_ActiveUser_DeleteUserSelf() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "deactivate.me@sun-strategy.com", + Active = true, + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + AuditUserDetails = new AuditUserDetails + { + UserId = 7, + UserDisplayName = "Testing User", + Comment = "Test comment" + }; + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.DeactivateUser(AuditUserDetails, existingUser.Email); }); + } + + [Test] + public async Task DeactivateUser_DeactivatedUser_ThrowsArgumentException() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "deactivate.me@sun-strategy.com", + Active = false, + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.DeactivateUser(AuditUserDetails, existingUser.Email); }); + } + + [Test] + public Task DeactivateUser_UserNotFound_ThrowsEmailNotFoundException() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "doesnot.exist@sun-strategy.com", + Active = false, + }; + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.DeactivateUser(AuditUserDetails, existingUser.Email); }); + return Task.CompletedTask; + } + + [Test] + public async Task DeactivateUser_GeneralIDRefVersionActiveUser_DeactivatesUser() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "deactivate.me@sun-strategy.com", + Active = true, + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var generalIdRef = new GeneralIdRef + { + Id = 7 + }; + + //Act + await UserManager.DeactivateUser(AuditUserDetails, generalIdRef, CancellationToken.None); + + //Assert + var user = UserManagerRepository.Users.Single(x => x.Email == existingUser.Email); + Assert.That(user.Active, Is.False); + } + + [Test] + public async Task DeactivateUser_GeneralIDRefVersionDeactivatedUser_ThrowsArgumentException() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "deactivate.me@sun-strategy.com", + Active = false, + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var generalIdRef = new GeneralIdRef + { + Id = 7 + }; + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.DeactivateUser(AuditUserDetails, generalIdRef, CancellationToken.None); }); + } + + [Test] + public Task DeactivateUser_GeneralIDRefVersionUserNotFound_ThrowsEmailNotFoundException() + { + //Arrange + var existingUser = new User + { + Id = 7, + Email = "doesnot.exist@sun-strategy.com", + Active = false, + }; + + var generalIdRef = new GeneralIdRef + { + Id = 7 + }; + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.DeactivateUser(AuditUserDetails, generalIdRef, CancellationToken.None); }); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/EditUserUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/EditUserUnitTests.cs new file mode 100644 index 0000000..c4516b0 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/EditUserUnitTests.cs @@ -0,0 +1,179 @@ +using System.Data; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class EditUserUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task EditUser_ExistingUser_UpdatesCorrectly() + { + //Arrange + var domain = UserManagerRepository.Domains[1]; + + var user = new User + { + Id = 8472, + Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"), + DomainId = domain.Id, + Domain = domain + }; + + UserManagerRepository.Users.Add(user); + + var editUser = new EditUser + { + Id = new GeneralIdRef + { + Guid = user.Guid + }, + Domain = domain.ToGeneralIdRef()!, + FirstName = "Testy", + LastName = "McTester", + MiddleNames = "The Tested", + Email = "Testy@tester.tested" + }; + + //Act + await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None); + + //Assert + var result = UserManagerRepository.Users.Single(x => x.Guid == user.Guid); + + Assert.Multiple(() => + { + Assert.That(result.Guid, Is.EqualTo(user.Guid)); + Assert.That(result.Id, Is.EqualTo(user.Id)); + Assert.That(result.DomainId, Is.EqualTo(domain.Id)); + Assert.That(result.Domain, Is.EqualTo(domain)); + Assert.That(result.Active, Is.EqualTo(true)); + Assert.That(result.Email, Is.EqualTo(editUser.Email)); + Assert.That(result.FirstName, Is.EqualTo(editUser.FirstName)); + Assert.That(result.MiddleNames, Is.EqualTo(editUser.MiddleNames)); + Assert.That(result.LastName, Is.EqualTo(editUser.LastName)); + }); + } + + [Test] + public void EditUser_ExistingUserIsDeleted_ThrowsException() + { + //Arrange + var domain = UserManagerRepository.Domains[1]; + + var user = new User + { + Id = 8472, + Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"), + DomainId = domain.Id, + Domain = domain, + Active = false + }; + + UserManagerRepository.Users.Add(user); + + var editUser = new EditUser + { + Id = new GeneralIdRef + { + Guid = user.Guid + }, + Domain = domain.ToGeneralIdRef()!, + FirstName = "Testy", + LastName = "McTester", + MiddleNames = "The Tested", + Email = "Testy@tester.tested" + }; + + //Act & Assert + var result = Assert.ThrowsAsync(async () => + await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None) + ); + + Assert.That(result!.Message, Is.EqualTo("This user is inactive so cannot be modified. You will need to create the user again.")); + } + + [Test] + public void EditUser_UserDoesNotExist_ThrowsNotFoundException() + { + //Arrange + var domain = UserManagerRepository.Domains[1]; + + var user = new User + { + Id = 8472, + Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"), + DomainId = domain.Id, + Domain = domain + }; + + var editUser = new EditUser + { + Id = new GeneralIdRef + { + Guid = user.Guid + }, + Domain = domain.ToGeneralIdRef()!, + }; + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None); + }); + + Assert.That(result!.Message, Is.EqualTo("unable to find user")); + } + + [Test] + public void EditUser_UserDomainDoesNotExist_ThrowsNotFoundException() + { + //Arrange + var domain = UserManagerRepository.Domains[1]; + + var user = new User + { + Id = 8472, + Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"), + DomainId = domain.Id, + Domain = domain + }; + + UserManagerRepository.Users.Add(user); + + var editUser = new EditUser + { + Id = new GeneralIdRef + { + Guid = user.Guid + }, + Domain = new GeneralIdRef + { + Id = 700 + }, + }; + + //Assert + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None); + }); + + Assert.That(result!.Message, Is.EqualTo("unable to find domain")); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/ForgotPasswordUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/ForgotPasswordUnitTests.cs new file mode 100644 index 0000000..e4915c9 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/ForgotPasswordUnitTests.cs @@ -0,0 +1,124 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.MailService; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class ForgotPasswordUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public Task ForgotPassword_UserNotFound_ReturnsFailed() + { + //Arrange + var email = "fred@bloggs.com"; //User does not exist in fake database. + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.ForgotPassword(email); }); + return Task.CompletedTask; + } + + [Test] + public async Task ForgotPassword_User_ReturnsSuccess() + { + //Arrange + var existingUser = new User + { + Id = 9, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true, + Active = true, + FirstName = "Test", + LastName = "User" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Act + await UserManager.ForgotPassword(existingUser.Email); + + //Assert that the new row was added to the database correctly. + var emailUserAction = UserManagerRepository.EmailUserActions.SingleOrDefault(x => x.User.Email == existingUser.Email); + + Assert.That(emailUserAction, Is.Not.Null); + Assert.That(emailUserAction?.EmailActionType, Is.EqualTo(EmailUserActionType.PasswordReset)); + Assert.That(emailUserAction?.User.Email, Is.EqualTo(existingUser.Email)); + Assert.That(emailUserAction?.Token, Is.Not.Empty); + + //Assert that the e-mail request was sent. + MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(actualMailRequest, Is.Not.Null); + Assert.That(actualMailRequest.EmailType, Is.EqualTo(MailType.PasswordReset)); + Assert.That(actualMailRequest.To.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.To[0].DisplayName, Is.EqualTo(existingUser.DisplayName)); + Assert.That(actualMailRequest.To[0].Email, Is.EqualTo(existingUser.Email)); + Assert.That(actualMailRequest.Parameters.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.Parameters["url"], Is.Not.Empty); + } + + [Test] + public async Task ForgotPassword_User_EmailNotConfirmedReturnsException() + { + //Arrange + var existingUser = new User + { + Id = 9, + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Active = true, + FirstName = "Test", + LastName = "User" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + Assert.ThrowsAsync(async () => { await UserManager.ForgotPassword(existingUser.Email); }); + } + + + [Test] + public async Task ForgotPassword_DeactivatedUser_ReturnsFailed() + { + //Arrange + var existingUser = new User + { + Id = 9, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true, + Active = false, + FirstName = "Test", + LastName = "User" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await UserManager.ForgotPassword(existingUser.Email); + }); + + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetCurrentEmailActionUrlUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetCurrentEmailActionUrlUnitTests.cs new file mode 100644 index 0000000..db804f2 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetCurrentEmailActionUrlUnitTests.cs @@ -0,0 +1,135 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetCurrentEmailActionUrlUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public Task GetCurrentEmailActionUrl_UserNotFound_ThrowsNotFoundException() + { + //Arrange + var email = "missing@lost.island"; + + //Act & Assert + var exception = Assert.ThrowsAsync(async () => + { + await UserManager.GetCurrentEmailActionUrl(email, EmailUserActionType.ConfirmEmailAddress, + CancellationToken.None); + }); + + Assert.That(exception?.Message, Is.EqualTo("User not found")); + return Task.CompletedTask; + } + + [Test] + public async Task GetCurrentEmailActionUrl_EmailActionNotExists_ThrowsNotFoundException() + { + //Arrange + var existingUser = new User + { + Id = 9, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true, + Active = true, + FirstName = "Test", + LastName = "User" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act & Assert + var exception = Assert.ThrowsAsync(async () => + { + await UserManager.GetCurrentEmailActionUrl(existingUser.Email, EmailUserActionType.ConfirmEmailAddress, + CancellationToken.None); + }); + + Assert.That(exception?.Message, Is.EqualTo("Email action not found")); + } + + [Test] + public async Task GetCurrentEmailActionUrl_EmailActionHasExpired_ThrowsNotFoundException() + { + //Arrange + var existingUser = new User + { + Id = 9, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true, + Active = true, + FirstName = "Test", + LastName = "User" + }; + + _fakeClock.DateTime = new DateTimeOffset(2024, 01, 14, 1, 2, 3, TimeSpan.Zero); + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var emailUserAction = new EmailUserAction() + { + UserId = existingUser.Id, + EmailActionType = EmailUserActionType.ConfirmEmailAddress, + Created = new DateTimeOffset(2024, 01, 1, 1, 2, 3, TimeSpan.Zero), + Expires = new DateTimeOffset(2024, 01, 3, 1, 2, 3, TimeSpan.Zero), + }; + + UserManagerRepository.EmailUserActions.Add(emailUserAction); + + + //Act & Assert + var exception = Assert.ThrowsAsync(async () => + { + await UserManager.GetCurrentEmailActionUrl(existingUser.Email, EmailUserActionType.ConfirmEmailAddress, + CancellationToken.None); + }); + + Assert.That(exception?.Message, Is.EqualTo("Email action not found")); + } + + [Test] + public async Task GetCurrentEmailActionUrl_EmailActionInDate_ThrowsNotFoundException() + { + //Arrange + var expectedResult = + "https://esuite.test/emailuseraction/eyJlbWFpbCI6InRlc3R1c2VyQHN1bi1zdHJhdGVneS5jb20iLCJ0b2tlbiI6IjAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCIsInBhc3N3b3JkIjoiIiwiZW1haWxBY3Rpb25UeXBlIjoyfQ=="; + + var existingUser = new User + { + Id = 9, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true, + Active = true, + FirstName = "Test", + LastName = "User" + }; + + _fakeClock.DateTime = new DateTimeOffset(2024, 01, 14, 1, 2, 3, TimeSpan.Zero); + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var emailUserAction = new EmailUserAction() + { + UserId = existingUser.Id, + EmailActionType = EmailUserActionType.ConfirmEmailAddress, + Created = new DateTimeOffset(2024, 01, 14, 1, 2, 3, TimeSpan.Zero), + Expires = new DateTimeOffset(2024, 01, 16, 1, 2, 3, TimeSpan.Zero), + }; + + UserManagerRepository.EmailUserActions.Add(emailUserAction); + + //Act & Assert + var result = await UserManager.GetCurrentEmailActionUrl(existingUser.Email, EmailUserActionType.ConfirmEmailAddress, CancellationToken.None); + Assert.That(result, Is.EqualTo(expectedResult)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetProfileUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetProfileUnitTests.cs new file mode 100644 index 0000000..b6b67b0 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetProfileUnitTests.cs @@ -0,0 +1,72 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetProfileUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public Task GetProfile_UserNotExists_ThrowsError() + { + //Arrange + const string email = "non.existant@sun-strategy.com"; + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.GetProfile(email); }); + return Task.CompletedTask; + } + + [Test] + public async Task GetProfile_UserExists_ReturnsProfile() + { + //Arrange + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + Domain = new Domain + { + Name = "TestDomain" + } + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var profile = await UserManager.GetProfile(existingUser.Email); + + //Assert + Assert.That( existingUser.Email, Is.EqualTo(profile.Email)); + } + + [Test] + public async Task GetProfile_UsesTwoFactorAuthentication_DoesNotGenerateNewCode() + { + //Arrange + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + Domain = new Domain + { + Name = "TestDomain" + }, + UsingTwoFactorAuthentication = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var profile = await UserManager.GetProfile(existingUser.Email); + + //Assert + RandomNumberGeneratorMock.Verify(x => x.GetBytes(It.IsAny()), Times.Never); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetSsoProviderByIdUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetSsoProviderByIdUnitTests.cs new file mode 100644 index 0000000..55d55be --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetSsoProviderByIdUnitTests.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetSsoProviderByIdUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetProfile_UserExists_ReturnsSsoProvider() + { + //Arrange + var ssoProviderId = 1; + + //Act + var ssoProvider = await UserManager.GetSsoProviderById(ssoProviderId, CancellationToken.None); + + //Assert + Assert.That(ssoProvider, Is.Not.Null); + } + + [Test] + public async Task GetProfile_UserExists_ReturnsNull() + { + //Arrange + var ssoProviderId = 2; + + //Act + var ssoProvider = await UserManager.GetSsoProviderById(ssoProviderId, CancellationToken.None); + + //Assert + Assert.That(ssoProvider, Is.Null); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetSsoProviderForEmailUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetSsoProviderForEmailUnitTests.cs new file mode 100644 index 0000000..2b07169 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetSsoProviderForEmailUnitTests.cs @@ -0,0 +1,86 @@ +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetSsoProviderForEmailUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetProfile_UserExists_ReturnsSsoProvider() + { + //Arrange + var actualSsoProvider = UserManagerRepository.SsoProviders.First(); + + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + SsoProviderId = actualSsoProvider.Id, + SsoProvider = actualSsoProvider + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var ssoProvider = await UserManager.GetSsoProviderForEmail(existingUser.Email, CancellationToken.None); + + //Assert + Assert.That(ssoProvider, Is.EqualTo(actualSsoProvider)); + } + + [Test] + public async Task GetProfile_UserExists_ReturnsNull() + { + //Arrange + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var ssoProvider = await UserManager.GetSsoProviderForEmail(existingUser.Email, CancellationToken.None); + + //Assert + Assert.That(ssoProvider, Is.Null); + } + + [Test] + public async Task GetProfile_UserHasdomainLevelSsoProvider_ReturnsSsoProvider() + { + //Arrange + var actualSsoProvider = UserManagerRepository.SsoProviders.First(); + + var domain = new Domain + { + Id = 100, + SsoProvider = actualSsoProvider, + SsoProviderId = actualSsoProvider.Id + }; + + DomainRepository.Domains.Add(domain); + + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + DomainId = domain.Id + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var ssoProvider = await UserManager.GetSsoProviderForEmail(existingUser.Email, CancellationToken.None); + + //Assert + Assert.That(ssoProvider, Is.EqualTo(actualSsoProvider)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserAsyncUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserAsyncUnitTests.cs new file mode 100644 index 0000000..321e4fa --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserAsyncUnitTests.cs @@ -0,0 +1,55 @@ +using e_suite.API.Common.exceptions; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetUserAsyncUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetUserAsync_WhenUserDoesNotExist_ReturnsNotFoundError() + { + // Arrange + var userId = new GeneralIdRef { Id = 1000000 }; + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + var result = await UserManager.GetUserAsync(userId, default); + }); + } + + [Test] + public async Task GetUserAsync_WhenUserExists_ReturnsUser() + { + // Arrange + var userId = new GeneralIdRef { Id = -1 }; + + // Act + var result = await UserManager.GetUserAsync(userId, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result!.Guid, Is.EqualTo(new Guid("{EA6A2EB2-ADBF-47A1-8FA6-EF363D0750DC}"))); + Assert.That(result!.FirstName, Is.EqualTo("Audit")); + Assert.That(result!.LastName, Is.EqualTo("Tester")); + Assert.That(result!.MiddleNames, Is.EqualTo("")); + Assert.That(result!.DisplayName, Is.EqualTo("Audit Tester")); + Assert.That(result!.Email, Is.EqualTo("audit@test.test")); + Assert.That(result!.Created, Is.EqualTo(new DateTimeOffset(2023, 7, 24, 13, 45, 24, TimeSpan.Zero))); + Assert.That(result!.LastUpdated, Is.EqualTo(new DateTimeOffset(2023, 7, 24, 13, 45, 25, TimeSpan.Zero))); + Assert.That(result!.Domain.Id, Is.EqualTo(1)); + Assert.That(result!.Domain.Guid, Is.EqualTo(new Guid("E5B6C043-C2EB-46CC-9387-E5F45420C93F"))); + Assert.That(result!.DomainName, Is.EqualTo("Default Test domain")); + Assert.That(result!.EmailConfirmed, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserByEmailAsyncUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserByEmailAsyncUnitTests.cs new file mode 100644 index 0000000..e2e2e6e --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserByEmailAsyncUnitTests.cs @@ -0,0 +1,54 @@ +using e_suite.API.Common.exceptions; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetUserByEmailAsyncUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void GetUserAsync_WhenUserDoesNotExist_ReturnsNotFoundError() + { + // Arrange + var email = "test@test.test"; + + // Assert + Assert.ThrowsAsync(async () => + { + // Act + var result = await UserManager.GetUserByEmailAsync(email, default); + }); + } + + [Test] + public async Task GetUserAsync_WhenUserExists_ReturnsUser() + { + // Arrange + var email = "audit@test.test"; + + // Act + var result = await UserManager.GetUserByEmailAsync(email, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result!.Guid, Is.EqualTo(new Guid("{EA6A2EB2-ADBF-47A1-8FA6-EF363D0750DC}"))); + Assert.That(result!.FirstName, Is.EqualTo("Audit")); + Assert.That(result!.LastName, Is.EqualTo("Tester")); + Assert.That(result!.MiddleNames, Is.EqualTo("")); + Assert.That(result!.DisplayName, Is.EqualTo("Audit Tester")); + Assert.That(result!.Email, Is.EqualTo("audit@test.test")); + Assert.That(result!.Created, Is.EqualTo(new DateTimeOffset(2023, 7, 24, 13, 45, 24, TimeSpan.Zero))); + Assert.That(result!.LastUpdated, Is.EqualTo(new DateTimeOffset(2023, 7, 24, 13, 45, 25, TimeSpan.Zero))); + Assert.That(result!.Domain.Id, Is.EqualTo(1)); + Assert.That(result!.Domain.Guid, Is.EqualTo(new Guid("E5B6C043-C2EB-46CC-9387-E5F45420C93F"))); + Assert.That(result!.Domain.Name, Is.EqualTo("Default Test domain")); + Assert.That(result!.EmailConfirmed, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserWithSingleUseGuidUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserWithSingleUseGuidUnitTests.cs new file mode 100644 index 0000000..dddf1c2 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUserWithSingleUseGuidUnitTests.cs @@ -0,0 +1,69 @@ +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetUserWithSingleUseGuidUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetUserWithSingleUseGuid_GuidExists_ReturnsUserAndDeletedSingleUseGuid() + { + //Arrange + var user = new User + { + Id = 2, + Email = "testuser@sun-strategy.com" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + var guid = new Guid("{91995044-F53D-4552-B154-2C33113417CD}"); + + var testSingleUseGuid = new SingleUseGuid + { + Id = 1, + Guid = guid, + UserId = user.Id, + User = user, + Expires = _fakeClock.GetNow.AddHours(1) + }; + + UserManagerRepository.SingleUseGuids.Add(testSingleUseGuid); + + //Act + var result = await UserManager.GetUserWithSingleUseGuid(guid, CancellationToken.None); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That( UserManagerRepository.SingleUseGuids.Contains(testSingleUseGuid), Is.False); + } + + [Test] + public async Task GetUserWithSingleUseGuid_GuidDoesNotExist_ReturnsNull() + { + //Arrange + var user = new User + { + Id = 2, + Email = "testuser@sun-strategy.com" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + var guid = new Guid("{91995044-F53D-4552-B154-2C33113417CD}"); + + //Act + var result = await UserManager.GetUserWithSingleUseGuid(guid, CancellationToken.None); + + //Assert + Assert.That(result, Is.Null); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUsersAsyncUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUsersAsyncUnitTests.cs new file mode 100644 index 0000000..e61e563 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/GetUsersAsyncUnitTests.cs @@ -0,0 +1,31 @@ +using e_suite.Utilities.Pagination; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class GetUsersAsyncUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task GetUsersAsync_WhenCalledWithNoSpecificParameters_ReturnsPageOfResults() + { + // Arrange + var paging = new Paging(); + + // Act + var result = await UserManager.GetUsersAsync(paging, default); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Data, Is.Not.Null); + Assert.That(result.Data.Count(), Is.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LinkSsoProfileToUserUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LinkSsoProfileToUserUnitTests.cs new file mode 100644 index 0000000..aa877ca --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LinkSsoProfileToUserUnitTests.cs @@ -0,0 +1,148 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class LinkSsoProfileToUserUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LinkSsoProfileToUser_UserExists_LinksSsoProividerToUser() + { + //Arrange + var user = new User + { + Email = "testuser@sun-strategy.com", + Domain = new Domain() + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + var ssoSubject = "ssoUserId12345"; + + //Act + await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, ssoSubject, false, CancellationToken.None); + + //Assert + Assert.That(user.SsoProviderId, Is.EqualTo(1)); + Assert.That(user.SsoProvider, Is.Null); + Assert.That(user.SsoSubject, Is.EqualTo(ssoSubject)); + } + + [Test] + public async Task LinkSsoProfileToUser_DomainLevelSsoProvider_DoesNotSetUserSsoProviderId() + { + //Arrange + var user = new User + { + Email = "testuser@sun-strategy.com", + Domain = new Domain{ SsoProviderId = 1} + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + var ssoSubject = "ssoUserId12345"; + + //Act + await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, user.Domain.SsoProviderId.Value, ssoSubject, false, CancellationToken.None); + + //Assert + Assert.That(user.SsoProviderId, Is.Null); + Assert.That(user.SsoProvider, Is.Null); + Assert.That(user.SsoSubject, Is.EqualTo(ssoSubject)); + } + + [TestCase(false)] + [TestCase(true)] + public async Task LinkSsoProfileToUser_setEmailConfirmedIsFalse_DoesNotChangeTheValueOfEmailConfirmed( bool emailConfirmed) + { + //Arrange + var user = new User + { + Email = "testuser@sun-strategy.com", + EmailConfirmed = emailConfirmed, + Domain = new Domain() + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + var ssoSubject = "ssoUserId12345"; + + //Act + await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, ssoSubject, false, CancellationToken.None); + + //Assert + Assert.That(user.EmailConfirmed, Is.EqualTo(emailConfirmed)); + } + + [Test] + public async Task LinkSsoProfileToUser_setEmailConfirmedIsTrue_SetsEmailConfirmedTrue() + { + //Arrange + var user = new User + { + Email = "testuser@sun-strategy.com", + EmailConfirmed = false, + Domain = new Domain() + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + var ssoSubject = "ssoUserId12345"; + + //Act + await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, ssoSubject, true, CancellationToken.None); + + //Assert + Assert.That(user.EmailConfirmed, Is.EqualTo(true)); + } + + [Test] + public void LinkSsoProfileToUser_UserIsNull_ThrowsNullReferenceException() + { + //Arrange + var actualSsoProvider = UserManagerRepository.SsoProviders.First(); + + User user = null!; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, "ssoUserId12345", false, CancellationToken.None); + }); + } + + [Test] + public async Task LinkSsoProfileToUser_SsoProviderIdInvalid_ThrowsNotFoundException() + { + //Arrange + var actualSsoProvider = UserManagerRepository.SsoProviders.First(); + + var user = new User + { + Email = "testuser@sun-strategy.com", + Domain = new Domain() + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 2, "ssoUserId12345", false, CancellationToken.None); + }); + + Assert.That(user.SsoProvider, Is.Null); + Assert.That(user.SsoProviderId, Is.Null); + Assert.That(user.SsoSubject, Is.EqualTo(string.Empty)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LoginSsoUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LoginSsoUnitTests.cs new file mode 100644 index 0000000..23a09d8 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LoginSsoUnitTests.cs @@ -0,0 +1,75 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class LoginSsoUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LoginSso_UserNotFound_ReturnsFailed() + { + //Arrange + //Act + var result = await UserManager.LoginSso(1,"1",CancellationToken.None); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + } + + [Test] + public async Task LoginSso_EmailNotConfirmed_ReturnsError() + { + //Arrange + var existingUser = new User + { + Id = 16, + Email = "testuser2@sun-strategy.com", + Password = "testing", + EmailConfirmed = false, + SsoSubject = "10", + SsoProviderId = 1 + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + + //Act + var result = await UserManager.LoginSso(existingUser.SsoProviderId.Value, existingUser.SsoSubject, CancellationToken.None); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.EmailNotConfirmed)); + } + + + [Test] + public async Task LoginSso_AccountIsNotActive_ReturnsFailed() + { + //Arrange + var existingUser = new User + { + Id = 15, + Email = "testuser@sun-strategy.com", + Password = "testing", + EmailConfirmed = true, + Active = false, + SsoSubject = "10", + SsoProviderId = 1 + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var result = await UserManager.LoginSso(existingUser.SsoProviderId.Value, existingUser.SsoSubject, CancellationToken.None); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + Assert.That(result.Token, Is.Empty); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LoginUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LoginUnitTests.cs new file mode 100644 index 0000000..2d6268e --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/LoginUnitTests.cs @@ -0,0 +1,345 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Nuget.PasswordHasher; +using eSuite.Core.MailService; +using Microsoft.AspNetCore.Identity; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class LoginUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task Login_UserNotFound_ReturnsFailed() + { + //Arrange + var login = new Login + { + Email = "fred@bloggs.com" //User does not exist in fake database. + }; + + //Act + var result = await UserManager.Login(login); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + } + + [Test] + public async Task Login_VerifyHashedPasswordFails_ReturnsNull() + { + //Arrange + var existingUser = new User + { + Id = 15, + Email = "testuser@sun-strategy.com", + Password = "testing", + EmailConfirmed = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing" + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Failed); + + //Act + var result = await UserManager.Login(login); + + //Assert + CustomPasswordHasherMock.Verify(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password), Times.Once); + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + } + + [Test] + public async Task Login_VerifyHashedPasswordMatches_ReturnsSuccess() + { + //Arrange + var existingUser = new User + { + Id = 15, + Email = "testuser@sun-strategy.com", + Password = "testing", + EmailConfirmed = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing" + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + + //Act + var result = await UserManager.Login(login); + + //Assert + CustomPasswordHasherMock.Verify(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password), Times.Once); + CustomPasswordHasherMock.Verify(x => x.HashPassword(It.IsAny(), login.Password), Times.Never); + Assert.That(result.Result, Is.EqualTo(LoginResult.Success)); + Assert.That(result.Token, Is.Not.Empty); + } + + [Test] + public async Task Login_VerifyHashedPasswordRequestsRehash_ReturnsSuccessAndRehashesPassword() + { + //Arrange + var existingUser = new User + { + Id = 14, + Email = "testuser@sun-strategy.com", + Password = "testing", + EmailConfirmed = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing" + }; + + var newHashedPassword = "123456"; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.SuccessRehashNeeded); + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), login.Password)).Returns(newHashedPassword); + + //Act + var result = await UserManager.Login(login); + + //Assert + CustomPasswordHasherMock.Verify(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password), Times.Once); + CustomPasswordHasherMock.Verify(x => x.HashPassword(It.IsAny(), login.Password), Times.Once); + Assert.That(result.Result, Is.EqualTo(LoginResult.Success)); + Assert.That(result.Token, Is.Not.Empty); + } + + [Test] + public async Task Login_EmailNotConfirmed_ReturnsError() + { + //Arrange + var existingUser = new User + { + Id = 16, + Email = "testuser2@sun-strategy.com", + Password = "testing", + EmailConfirmed = false + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing" + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + + //Act + var result = await UserManager.Login(login); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.EmailNotConfirmed)); + } + + [Test] + public async Task Login_RequestTfaDisable_ReturnsTwoFactorAuthenticationRemovalRequested() + { + //Arrange + var existingUser = new User + { + Id = 16, + Email = "testuser3@sun-strategy.com", + Password = "testing", + EmailConfirmed = true, + UsingTwoFactorAuthentication = true, + FirstName = "Test3", + LastName = "User" + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing", + RequestTfaRemoval = true + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Act + var result = await UserManager.Login(login); + + //Assert that the new row was added to the database correctly. + var emailUserAction = UserManagerRepository.EmailUserActions.SingleOrDefault(x => x.User.Email == login.Email); + + Assert.That(emailUserAction, Is.Not.Null); + Assert.That(emailUserAction?.EmailActionType, Is.EqualTo(EmailUserActionType.DisableAuthenticator)); + Assert.That(emailUserAction?.User.Email, Is.EqualTo(login.Email)); + Assert.That(emailUserAction?.Token, Is.Not.Empty); + + //Assert that the e-mail request was sent. + MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(actualMailRequest, Is.Not.Null); + Assert.That(actualMailRequest.EmailType, Is.EqualTo(MailType.DisableAuthenticator)); + Assert.That(actualMailRequest.To.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.To[0].DisplayName, Is.EqualTo(existingUser.DisplayName)); + Assert.That(actualMailRequest.To[0].Email, Is.EqualTo(login.Email)); + Assert.That(actualMailRequest.Parameters.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.Parameters["url"], Is.Not.Empty); + + Assert.That(result.Result, Is.EqualTo(LoginResult.TwoFactorAuthenticationRemovalRequested)); + } + + [Test] + public async Task Login_TfaEnabledButCodeNotProvided_ReturnsTwoFactorAuthenticationCodeRequired() + { + //Arrange + var existingUser = new User + { + Id = 16, + Email = "testuser3@sun-strategy.com", + Password = "testing", + EmailConfirmed = true, + UsingTwoFactorAuthentication = true, + FirstName = "Test3", + LastName = "User" + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing", + RequestTfaRemoval = false + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + + //Act + var result = await UserManager.Login(login); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.TwoFactorAuthenticationCodeRequired)); + } + + [Test] + public async Task Login_TfaEnabledButCodeIncorrect_ReturnsTwoFactorAuthenticationCodeIncorrect() + { + //Arrange + var existingUser = new User + { + Id = 16, + Email = "testuser3@sun-strategy.com", + Password = "testing", + EmailConfirmed = true, + UsingTwoFactorAuthentication = true, + FirstName = "Test3", + LastName = "User" + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing", + RequestTfaRemoval = false, + SecurityCode = "123456" + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + + //Act + var result = await UserManager.Login(login); + + //Assert + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), login.SecurityCode, false), Times.Once); + + Assert.That(result.Result, Is.EqualTo(LoginResult.TwoFactorAuthenticationCodeIncorrect)); + } + + [Test] + public async Task Login_TfaEnabledAndCodeCorrect_ReturnsSuccess() + { + //Arrange + var existingUser = new User + { + Id = 16, + Email = "testuser3@sun-strategy.com", + Password = "testing", + EmailConfirmed = true, + UsingTwoFactorAuthentication = true, + FirstName = "Test3", + LastName = "User" + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = "testuser3@sun-strategy.com", //User exists in fake database. But email is not confirmed. + Password = "testing", + RequestTfaRemoval = false, + SecurityCode = "123456" + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), login.SecurityCode, It.IsAny())).Returns(true); + + //Act + var result = await UserManager.Login(login); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Success)); + Assert.That(result.Token, Is.Not.Empty); + } + + [Test] + public async Task Login_AccountIsNotActive_ReturnsFailed() + { + //Arrange + var existingUser = new User + { + Id = 15, + Email = "testuser@sun-strategy.com", + Password = "testing", + EmailConfirmed = true, + Active = false + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var login = new Login + { + Email = existingUser.Email, + Password = "testing" + }; + + CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny(), It.IsAny(), login.Password)).Returns(PasswordVerificationResult.Success); + + //Act + var result = await UserManager.Login(login); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + Assert.That(result.Token, Is.Empty); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/RefreshTokenByEmailUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/RefreshTokenByEmailUnitTests.cs new file mode 100644 index 0000000..2bd813c --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/RefreshTokenByEmailUnitTests.cs @@ -0,0 +1,68 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class RefreshTokenByEmailUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task RefreshToken_UserNotFound_ReturnsFailed() + { + //Arrange + var email = "fred@bloggs.com"; //User does not exist in fake database. + + //Act + var result = await UserManager.RefreshToken(email); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + } + + [Test] + public async Task RefreshToken_User_ReturnsSuccess() + { + //Arrange + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + EmailConfirmed = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var result = await UserManager.RefreshToken(existingUser.Email); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Success)); + Assert.That(result.Token, Is.Not.Empty); + } + + [Test] + public async Task RefreshToken_DeactivatedUser_ReturnsFailed() + { + //Arrange + var existingUser = new User + { + Email = "testuser@sun-strategy.com", + Active = false + + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + //Act + var result = await UserManager.RefreshToken(existingUser.Email); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + Assert.That(result.Token, Is.Empty); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/RefreshTokenByIdUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/RefreshTokenByIdUnitTests.cs new file mode 100644 index 0000000..f533409 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/RefreshTokenByIdUnitTests.cs @@ -0,0 +1,86 @@ +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Miscellaneous; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class RefreshTokenByIdUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task RefreshToken_UserNotFound_ReturnsFailed() + { + //Arrange + var id = new GeneralIdRef + { + Guid = null, + Id = 1 + }; + + //Act + var result = await UserManager.RefreshToken(id); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + } + + [Test] + public async Task RefreshToken_User_ReturnsSuccess() + { + //Arrange + var existingUser = new User + { + Id = 1, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var id = new GeneralIdRef + { + Guid = null, + Id = existingUser.Id + }; + + //Act + var result = await UserManager.RefreshToken(id); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Success)); + Assert.That(result.Token, Is.Not.Empty); + } + + [Test] + public async Task RefreshToken_DeactivatedUser_ReturnsFailed() + { + //Arrange + var existingUser = new User + { + Id = 1, + Email = "testuser@sun-strategy.com", + Active = false + + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var id = new GeneralIdRef + { + Guid = null, + Id = existingUser.Id + }; + //Act + var result = await UserManager.RefreshToken(id); + + //Assert + Assert.That(result.Result, Is.EqualTo(LoginResult.Failed)); + Assert.That(result.Token, Is.Empty); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/ResendConfirmEmailUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/ResendConfirmEmailUnitTests.cs new file mode 100644 index 0000000..7433aeb --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/ResendConfirmEmailUnitTests.cs @@ -0,0 +1,65 @@ +using e_suite.API.Common.exceptions; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class ResendConfirmEmailUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ResendConfirmEmail_UserNotFound_ThrowsNotFoundException() + { + //Arrange + var user = new GeneralIdRef + { + Guid = new Guid("f9977d27-423f-4d80-9c20-b379f5d08af4") + }; + + //Assert + Assert.ThrowsAsync(async () => + { + //Act + await UserManager.ResendConfirmEmail(AuditUserDetails, user, CancellationToken.None); + }); + } + + [Test] + public async Task ResendConfirmEmail_UserExists_SendsConfirmationEmail() + { + //Arrange + var user = new GeneralIdRef + { + Guid = new Guid("{EA6A2EB2-ADBF-47A1-8FA6-EF363D0750DC}") + }; + + MailRequest actualMailRequest = null!; + + MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny(), It.IsAny())) + .Callback((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; }); + + //Act + await UserManager.ResendConfirmEmail(AuditUserDetails, user, CancellationToken.None); + + //Assert + + //Assert that the e-mail request was sent. + MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(actualMailRequest, Is.Not.Null); + Assert.That(actualMailRequest.EmailType, Is.EqualTo(MailType.ConfirmEmailAddress)); + Assert.That(actualMailRequest.To.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.To[0].DisplayName, Is.EqualTo("Audit Tester")); + Assert.That(actualMailRequest.To[0].Email, Is.EqualTo("audit@test.test")); + Assert.That(actualMailRequest.Parameters.Count, Is.EqualTo(1)); + Assert.That(actualMailRequest.Parameters["url"], Is.Not.Empty); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/SetAuthenticationUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/SetAuthenticationUnitTests.cs new file mode 100644 index 0000000..a27a832 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/SetAuthenticationUnitTests.cs @@ -0,0 +1,214 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class SetAuthenticationUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void SetAuthentication_UserNotFound_ThrowsException() + { + //Arrange + var userAuthenticationDetails = new UserAuthenticationDetails() + { + Id = new GeneralIdRef + { + Id = 100 + } + + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.SetAuthentication(AuditUserDetails, userAuthenticationDetails, true, CancellationToken.None); + }); + } + + [Test] + public async Task SetAuthentication_PasswordSet_HashesPassword() + { + //Arrange + const string existingEmail = "testuser@sun-strategy.com"; + var existingUser = new User + { + Id = 12, + Email = existingEmail, + EmailConfirmed = false + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + + var userAuthenticationDetails = new UserAuthenticationDetails() + { + Id = new GeneralIdRef + { + Id = 12 + }, + Password = "This is my new password", + + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act & Assert + await UserManager.SetAuthentication(AuditUserDetails, userAuthenticationDetails, false, CancellationToken.None); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.Password, Is.EqualTo(hashedPassword)); + } + + [Test] + public async Task SetAuthentication_ConfirmEmail_SetsEmailConfirmedTrue() + { + //Arrange + const string existingEmail = "testuser@sun-strategy.com"; + var existingUser = new User + { + Id = 12, + Email = existingEmail, + EmailConfirmed = false + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + + var userAuthenticationDetails = new UserAuthenticationDetails() + { + Id = new GeneralIdRef + { + Id = 12 + } + }; + + //Act & Assert + await UserManager.SetAuthentication(AuditUserDetails, userAuthenticationDetails, true, CancellationToken.None); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.EmailConfirmed, Is.True); + } + + [Test] + public async Task SetAuthentication_EnablingTFANoSecurityCode_DoesNotEnableTFA() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + + var userAuthenticationDetails = new UserAuthenticationDetails() + { + Id = new GeneralIdRef + { + Id = 12 + }, + UsingTwoFactorAuthentication = true + }; + + //Act + await UserManager.SetAuthentication(AuditUserDetails, userAuthenticationDetails, true, CancellationToken.None); + + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.False); + + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public async Task SetAuthentication_EnablingTFAIncorrectSecurityCode_DoesNotEnableTFA() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var userAuthenticationDetails = new UserAuthenticationDetails() + { + Id = new GeneralIdRef + { + Id = 12 + }, + UsingTwoFactorAuthentication = true, + SecurityCode = "12345" + }; + + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), userAuthenticationDetails.SecurityCode, It.IsAny())).Returns(false); + + //Act + await UserManager.SetAuthentication(AuditUserDetails, userAuthenticationDetails, true, CancellationToken.None); + + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.False); + + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task SetAuthentication_EnablingTFACorrectSecurityCode_EnablesTFA() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var userAuthenticationDetails = new UserAuthenticationDetails() + { + Id = new GeneralIdRef + { + Id = 12 + }, + UsingTwoFactorAuthentication = true, + SecurityCode = "12345" + }; + + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), userAuthenticationDetails.SecurityCode, It.IsAny())).Returns(true); + + //Act + await UserManager.SetAuthentication(AuditUserDetails, userAuthenticationDetails, true, CancellationToken.None); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.True); + + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/TurnOfSsoForUserUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/TurnOfSsoForUserUnitTests.cs new file mode 100644 index 0000000..eb3f9d2 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/TurnOfSsoForUserUnitTests.cs @@ -0,0 +1,63 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.UserManager; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class TurnOfSsoForUserUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task TurnOfSsoForUser_UserExists_TurnsOffSsoForUser() + { + //Arrange + var actualSsoProvider = UserManagerRepository.SsoProviders.First(); + + var user = new User + { + Email = "testuser@sun-strategy.com", + SsoProvider = actualSsoProvider, + SsoProviderId = actualSsoProvider.Id, + SsoSubject = "SecretString123456" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, user, default); + + //Act + await UserManager.TurnOfSsoForUser(AuditUserDetails, user.ToGeneralIdRef()!, CancellationToken.None); + + //Assert + Assert.That(user.SsoProviderId, Is.Null); + Assert.That(user.SsoProvider, Is.Null); + Assert.That(user.SsoSubject, Is.EqualTo(string.Empty)); + } + + [Test] + public void TurnOfSsoForUser_UserNotFound_ThrowsNotFoundException() + { + //Arrange + var actualSsoProvider = UserManagerRepository.SsoProviders.First(); + + var user = new User + { + Email = "testuser@sun-strategy.com", + SsoProvider = actualSsoProvider, + SsoProviderId = actualSsoProvider.Id, + SsoSubject = "SecretString123456" + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + await UserManager.TurnOfSsoForUser(AuditUserDetails, user.ToGeneralIdRef()!, CancellationToken.None); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/UpdateProfileUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/UpdateProfileUnitTests.cs new file mode 100644 index 0000000..da6f11f --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManager/UpdateProfileUnitTests.cs @@ -0,0 +1,301 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.MailService; +using Moq; +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManager; + +[TestFixture] +public class UpdateProfileUnitTests : UserManagerTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task UpdateProfile_UpdatesMade_SavesChanges() + { + //Arrange + const string existingEmail = "testuser@sun-strategy.com"; + var existingUser = new User + { + Id = 12, + Email = existingEmail + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var updatedProfile = new UpdatedUserProfile + { + FirstName = "James", + MiddleNames = "Tiberius", + LastName = "Kirk", + UsingTwoFactorAuthentication = true, + Email = "james.t.kirk@enterprise.uss.fed" + }; + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.Email, Is.Not.EqualTo(existingEmail)); + Assert.That(alteredProfile?.Email, Is.EqualTo(updatedProfile.Email)); + } + + [Test] + public async Task UpdateProfile_NewPasswordSupplied_HashesNewPassword() + { + //Arrange + const string existingEmail = "testuser@sun-strategy.com"; + var existingUser = new User + { + Id = 12, + Email = existingEmail, + EmailConfirmed = true + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var updatedProfile = new UpdatedUserProfile + { + Email = existingEmail, + Password = "This is my new password", + }; + + var hashedPassword = "owekjhrtlkerjthbwerlkjrthbw3"; + CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny(), It.IsAny())) + .Returns(hashedPassword); + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.Password, Is.EqualTo(hashedPassword)); + MailServiceMock.Verify( x => x.RequestEMailAsync( It.IsAny(), It.IsAny() ), Times.Once); + } + + + [Test] + public async Task UpdateProfile_NewEmailExists_ThrowsError() + { + //Arrange + const string existingEmail = "testuser@sun-strategy.com"; + var existingUser = new User + { + Id = 12, + Email = existingEmail, + Domain = new Domain + { + Name = "TestDomain" + } + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + const string existing2Email = "testuser2@sun-strategy.com"; + var existingUser2 = new User + { + Id = 13, + Email = existing2Email + }; + await UserManagerRepository.AddUser(AuditUserDetails, existingUser2, default); + + var testProfile = await UserManager.GetProfile(existingUser.Email); + + var updatedProfile = new UpdatedUserProfile + { + Email = existing2Email + }; + + //Act & Assert + Assert.ThrowsAsync(async () => { await UserManager.UpdateProfile(AuditUserDetails, existingEmail, updatedProfile); }); + } + + [Test] + public async Task UpdateProfile_DisablingTFA_DisablesTFAAndChangesKey() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = true, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var newTwoFactorAuthenticationKey = "SecondKey"; + RandomNumberGeneratorMock.Setup(x => x.GetRandomString(It.IsAny())) + .Returns(newTwoFactorAuthenticationKey); + + var updatedProfile = new UpdatedUserProfile + { + Email = existingUser.Email, + UsingTwoFactorAuthentication = false + }; + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.False); + Assert.That(alteredProfile?.TwoFactorAuthenticationKey, Is.EqualTo(newTwoFactorAuthenticationKey)); + } + + [Test] + public async Task UpdateProfile_EnablingTFANoSecurityCode_DoesNotEnableTFA() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + + var updatedProfile = new UpdatedUserProfile + { + Email = existingUser.Email, + UsingTwoFactorAuthentication = true + }; + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.False); + + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public async Task UpdateProfile_EnablingTFAIncorrectSecurityCode_DoesNotEnableTFA() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var updatedProfile = new UpdatedUserProfile + { + Email = existingUser.Email, + UsingTwoFactorAuthentication = true, + SecurityCode = "12345" + }; + + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), updatedProfile.SecurityCode, It.IsAny())).Returns(false); + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.False); + + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task UpdateProfile_EnablingTFACorrectSecurityCode_EnablesTFA() + { + //Arrange + var existingUser = new User + { + Id = 12, + Email = "testuser@sun-strategy.com", + UsingTwoFactorAuthentication = false, + TwoFactorAuthenticationKey = "FirstKey" + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var updatedProfile = new UpdatedUserProfile + { + Email = existingUser.Email, + UsingTwoFactorAuthentication = true, + SecurityCode = "12345" + }; + + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), updatedProfile.SecurityCode, It.IsAny())).Returns(true); + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.UsingTwoFactorAuthentication, Is.True); + + TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task UpdateProfile_WhenEmailIsEmpty_DoesNotAttemptToChangeEmailAddress() + { + //Arrange + var existingUser = new User + { + Id = 13, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var updatedProfile = new UpdatedUserProfile + { + Email = string.Empty + }; + + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), updatedProfile.SecurityCode, It.IsAny())).Returns(true); + + //Act + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile); + + //Assert + var alteredProfile = UserManagerRepository.Users.SingleOrDefault(x => x.Id == existingUser.Id); + Assert.That(alteredProfile?.EmailConfirmed, Is.True); + } + + [Test] + public async Task UpdateProfile_WhenEmailIsNotValid_ThrowsExpectedException() + { + //Arrange + var existingUser = new User + { + Id = 13, + Email = "testuser@sun-strategy.com", + EmailConfirmed = true + }; + + await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default); + + var updatedProfile = new UpdatedUserProfile + { + Email = "invalid at invalid dot invalid" + }; + + TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny(), updatedProfile.SecurityCode, It.IsAny())).Returns(true); + + //Act & Assert + Assert.ThrowsAsync(async () => + await UserManager.UpdateProfile(AuditUserDetails, existingUser.Email, updatedProfile)); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/UserManager.UnitTests/UserManagerMaintenance/ClearOldEmailActionsUnitTests.cs b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManagerMaintenance/ClearOldEmailActionsUnitTests.cs new file mode 100644 index 0000000..8e1c8c5 --- /dev/null +++ b/e-suite.Modules.UserManager/UserManager.UnitTests/UserManagerMaintenance/ClearOldEmailActionsUnitTests.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; +using UserManager.UnitTests.Helpers; + +namespace UserManager.UnitTests.UserManagerMaintenance; + +[TestFixture] +public class ClearOldEmailActionsUnitTests : UserManagerMaintenanceTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ClearOldEmail() + { + //Arrange + + //Act + await UserManagerManagerMaintenance.ClearOldEmailActions(); + + //Assert + Assert.That(UserManagerRepository.DeleteExpiredEmailUserActionsCalled, Is.True); + } +} + +[TestFixture] +public class ClearOldSingleUserGuidsUnitTests : UserManagerMaintenanceTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task ClearOldSingleUserGuids() + { + //Arrange + + //Act + await UserManagerManagerMaintenance.ClearOldSingleUserGuids(); + + //Assert + Assert.That(UserManagerRepository.DeleteExpiredSingleUseGuidsCalled, Is.True); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/azure-pipelines.yml b/e-suite.Modules.UserManager/azure-pipelines.yml new file mode 100644 index 0000000..a9271dc --- /dev/null +++ b/e-suite.Modules.UserManager/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Modules.UserManager/e-suite.Modules.UserManager.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager.sln b/e-suite.Modules.UserManager/e-suite.Modules.UserManager.sln new file mode 100644 index 0000000..0c44080 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Modules.UserManager", "e-suite.Modules.UserManager\e-suite.Modules.UserManager.csproj", "{AF1C44D7-720C-40D7-90C9-7805EF42F740}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{362ABE7E-142D-40AD-BE3A-C7FCCEA872EC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{4EB453D9-D5BB-4137-B92D-1E5A89B173E5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserManager.UnitTests", "UserManager.UnitTests\UserManager.UnitTests.csproj", "{E9C1AFA0-60C6-425A-A801-1E5BC21DDAAB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AF1C44D7-720C-40D7-90C9-7805EF42F740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF1C44D7-720C-40D7-90C9-7805EF42F740}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF1C44D7-720C-40D7-90C9-7805EF42F740}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF1C44D7-720C-40D7-90C9-7805EF42F740}.Release|Any CPU.Build.0 = Release|Any CPU + {E9C1AFA0-60C6-425A-A801-1E5BC21DDAAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9C1AFA0-60C6-425A-A801-1E5BC21DDAAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9C1AFA0-60C6-425A-A801-1E5BC21DDAAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9C1AFA0-60C6-425A-A801-1E5BC21DDAAB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4EB453D9-D5BB-4137-B92D-1E5A89B173E5} = {362ABE7E-142D-40AD-BE3A-C7FCCEA872EC} + {E9C1AFA0-60C6-425A-A801-1E5BC21DDAAB} = {4EB453D9-D5BB-4137-B92D-1E5A89B173E5} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AA20440E-355B-472B-AEEE-C0ED820781B4} + EndGlobalSection +EndGlobal diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Extensions/StringExtensions.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Extensions/StringExtensions.cs new file mode 100644 index 0000000..b9fe8dc --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Extensions/StringExtensions.cs @@ -0,0 +1,9 @@ +namespace e_suite.Modules.UserManager.Extensions; + +public static class StringExtensions +{ + public static bool Contains(this string value, char[] chars) + { + return chars.Any(value.Contains); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/IRandomNumberGenerator.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/IRandomNumberGenerator.cs new file mode 100644 index 0000000..aad7809 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/IRandomNumberGenerator.cs @@ -0,0 +1,8 @@ +namespace e_suite.Modules.UserManager.Facade; + +public interface IRandomNumberGenerator +{ + void GetBytes(byte[] randomBytes); + + string GetRandomString(int length); +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/ITwoFactorAuthenticator.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/ITwoFactorAuthenticator.cs new file mode 100644 index 0000000..15bc848 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/ITwoFactorAuthenticator.cs @@ -0,0 +1,13 @@ +using System.Diagnostics.CodeAnalysis; +using Google.Authenticator; + +namespace e_suite.Modules.UserManager.Facade; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public interface ITwoFactorAuthenticator +{ + bool ValidateTwoFactorPIN(string authenticationKey, string securityCode, bool secretIsBase32 = false); + + SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey, + bool secretIsBase32, int qaPixelsPerModule = 3); +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/RandomNumberGeneratorFacade.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/RandomNumberGeneratorFacade.cs new file mode 100644 index 0000000..a1a7bb5 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/RandomNumberGeneratorFacade.cs @@ -0,0 +1,28 @@ +using System.Security.Cryptography; +using e_suite.Modules.UserManager.Utils; + +namespace e_suite.Modules.UserManager.Facade; + +public class RandomNumberGeneratorFacade : IRandomNumberGenerator +{ + private readonly RandomNumberGenerator _randomNumberGenerator; + + public RandomNumberGeneratorFacade() + { + _randomNumberGenerator = RandomNumberGenerator.Create(); + } + + public void GetBytes(byte[] randomBytes) + { + _randomNumberGenerator.GetBytes(randomBytes); + } + + public string GetRandomString(int length) + { + var randomBytes = new byte[length]; + _randomNumberGenerator.GetBytes(randomBytes); + + var key = Base32.Encode(randomBytes); + return key; + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/TwoFactorAuthenticatorFacade.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/TwoFactorAuthenticatorFacade.cs new file mode 100644 index 0000000..7205550 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Facade/TwoFactorAuthenticatorFacade.cs @@ -0,0 +1,23 @@ +using Google.Authenticator; + +namespace e_suite.Modules.UserManager.Facade; + +public class TwoFactorAuthenticatorFacade : ITwoFactorAuthenticator +{ + private readonly TwoFactorAuthenticator _twoFactorAuthenticator; + + public TwoFactorAuthenticatorFacade() + { + _twoFactorAuthenticator = new TwoFactorAuthenticator(); + } + + public bool ValidateTwoFactorPIN(string authenticationKey, string securityCode, bool secretIsBase32 = false) + { + return _twoFactorAuthenticator.ValidateTwoFactorPIN(authenticationKey, securityCode, secretIsBase32); + } + + public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey, bool secretIsBase32, int qaPixelsPerModule = 3 ) + { + return _twoFactorAuthenticator.GenerateSetupCode(issuer, accountTitleNoSpaces, accountSecretKey, secretIsBase32, qaPixelsPerModule); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/GlobalSuppressions.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/IocRegistration.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/IocRegistration.cs new file mode 100644 index 0000000..fd96adc --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/IocRegistration.cs @@ -0,0 +1,22 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.UserManager.Facade; +using e_suite.Modules.UserManager.Repository; +using e_suite.Modules.UserManager.Services; + +namespace e_suite.Modules.UserManager; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Repository/UserManagerRepository.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Repository/UserManagerRepository.cs new file mode 100644 index 0000000..b43d0f7 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Repository/UserManagerRepository.cs @@ -0,0 +1,178 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.Clock; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using e_suite.Database.Core.Models; + +namespace e_suite.Modules.UserManager.Repository; + +public class UserManagerRepository : RepositoryBase, IUserManagerRepository +{ + private readonly IClock _clock; + + public UserManagerRepository(IClock clock, IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + _clock = clock; + } + + public async Task GetUserByEmail(string loginEmail, CancellationToken cancellationToken) + { + var users = await GetUsers() + .Include( x => x.SsoProvider) + .Include( x => x.Domain) + .Where(u => u.Email.Equals(loginEmail)) + .ToListAsync(cancellationToken); + + return users.FirstOrDefault(); + } + + public async Task GetUserSsoId(long ssoId, string ssoUserId, CancellationToken cancellationToken) + { + var users = await GetUsers() + .Where(u => u.SsoProviderId.Equals(ssoId) && u.SsoSubject.Equals(ssoUserId)) + .ToListAsync(cancellationToken); + return users.FirstOrDefault(); + } + + public async Task GetUserByDomainSsoId(long domainSsoId, string ssoUserId, CancellationToken cancellationToken) + { + var users = await GetUsers() + .Where(u => u.Domain.SsoProviderId.Equals(domainSsoId) && u.SsoSubject.Equals(ssoUserId)) + .ToListAsync(cancellationToken); + return users.FirstOrDefault(); + } + + public async Task GetUserById(IGeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var user = await GetUsers().FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + if (user != null) + { + await DatabaseDbContext.Entry(user).ReloadAsync(cancellationToken); // re-fetch from DB + } + + return user; + } + + public async Task GetSsoProviderById(long id, CancellationToken cancellationToken) + { + return await GetSsoProviders() + .SingleOrDefaultAsync(x => x.Id.Equals(id), cancellationToken); + } + + public IQueryable GetSsoProviders() + { + return DatabaseDbContext.SsoProviders; + } + + public async Task SaveSingleUseGuidForUser( + SingleUseGuid singleUseGuid, + CancellationToken cancellationToken + ) + { + await DatabaseDbContext.SingleUseGuids.AddAsync(singleUseGuid, cancellationToken); + await DatabaseDbContext.NoAuditSaveChangesAsync(cancellationToken); + } + + public async Task GetUserBySingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + var singleUseGuid = await DatabaseDbContext.SingleUseGuids + .Where(x => x.Guid == guid && x.Expires >= _clock.GetNow) + .Include( x => x.User) + .ThenInclude( x => x.Domain) + .FirstOrDefaultAsync(cancellationToken); + + return singleUseGuid?.User; + } + + public async Task DeleteSingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + var singleUseGuid = await DatabaseDbContext.SingleUseGuids + .Where(x => x.Guid == guid) + .FirstOrDefaultAsync(cancellationToken); + + if (singleUseGuid != null) + { + DatabaseDbContext.SingleUseGuids.Remove(singleUseGuid); + await DatabaseDbContext.NoAuditSaveChangesAsync(cancellationToken); + } + } + + public async Task GetDomainById(GeneralIdRef domainId, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Domains.FindByGeneralIdRefAsync(domainId, cancellationToken); + } + + public async Task AddEmailUserAction(AuditUserDetails auditUserDetails, EmailUserAction emailConfirmation, + CancellationToken cancellationToken) + { + emailConfirmation.Created = _clock.GetNow; + await DatabaseDbContext.EmailUserActions.AddAsync(emailConfirmation, cancellationToken); + await DatabaseDbContext.SaveChangesAsync( auditUserDetails, cancellationToken ); + } + + public async Task GetCurrentEmailUserAction(long userId, EmailUserActionType emailUserActionType, CancellationToken cancellationToken) + { + var now = _clock.GetNow; + return await DatabaseDbContext.EmailUserActions.Where( + x => x.UserId == userId + && x.EmailActionType == emailUserActionType + && x.Expires > now) + .OrderByDescending( x => x.Expires) + .FirstOrDefaultAsync(cancellationToken); + } + + public async Task AddUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + user.Created = _clock.GetNow; + + await DatabaseDbContext.Users.AddAsync(user, cancellationToken); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task EditUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task GetEmailUserAction(Guid token, CancellationToken cancellationToken) + { + return await DatabaseDbContext.EmailUserActions + .Where(c => c.Token.Equals(token) + && c.Expires > _clock.GetNow) + .Include(c => c.User) + .SingleOrDefaultAsync(cancellationToken); + } + + public async Task DeleteEmailUserAction(AuditUserDetails auditUserDetails, EmailUserAction emailUserAction, CancellationToken cancellationToken) + { + DatabaseDbContext.EmailUserActions.Remove(emailUserAction); + await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); + } + + public async Task DeleteExpiredEmailUserActions() + { + var expiredActions = await DatabaseDbContext.EmailUserActions + .Where(c => c.Expires < _clock.GetNow).ToListAsync(); + DatabaseDbContext.EmailUserActions.RemoveRange(expiredActions); + await DatabaseDbContext.NoAuditSaveChangesAsync(); + } + + public async Task DeleteExpiredSingleUseGuids() + { + var expiredGuids = await DatabaseDbContext.SingleUseGuids + .Where( x => x.Expires < _clock.GetNow).ToListAsync(); + DatabaseDbContext.SingleUseGuids.RemoveRange(expiredGuids); + await DatabaseDbContext.NoAuditSaveChangesAsync(); + } + + public IQueryable GetUsers() + { + return DatabaseDbContext.Users + .Include( x => x.Domain); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/ESuiteClaimTypes.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/ESuiteClaimTypes.cs new file mode 100644 index 0000000..75a83ca --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/ESuiteClaimTypes.cs @@ -0,0 +1,8 @@ +namespace e_suite.Modules.UserManager.Services; + +public static class ESuiteClaimTypes +{ + public const string DomainId = "domainid"; + + public const string SecurityPrivileges = "securityPrivileges"; +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/IJwtService.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/IJwtService.cs new file mode 100644 index 0000000..ce393b8 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/IJwtService.cs @@ -0,0 +1,13 @@ +using e_suite.Database.Core.Tables.UserManager; + +namespace e_suite.Modules.UserManager.Services; + +public interface IJwtService +{ + /// + /// Creates a valid JWT Security token for the provided User. + /// + /// + /// + string GenerateSecurityToken(User user); +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/JwtService.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/JwtService.cs new file mode 100644 index 0000000..c52fa79 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Services/JwtService.cs @@ -0,0 +1,79 @@ +using e_suite.API.Common; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.UserManager.Utils; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace e_suite.Modules.UserManager.Services; + +/// +/// Json Web Token Service +/// +public class JwtService : IJwtService +{ + private readonly IRoleManager _roleManager; + + private readonly string _secret; + private readonly string _expDate; + private readonly string _audience; + private readonly string _issuer; + + /// + /// default constructor using dependency injection. + /// + /// + public JwtService(IConfiguration config, IRoleManager roleManager) + { + _roleManager = roleManager; + var jwtConfig = config.GetSection("JwtConfig"); + + _secret = jwtConfig["secret"]!; + _expDate = jwtConfig["expirationInMinutes"]!; + _audience = jwtConfig["audience"]!; + _issuer = jwtConfig["issuer"]!; + } + + /// + /// Creates a valid JWT Security token for the provided User. + /// + /// + /// + public string GenerateSecurityToken(User user) + { + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.UTF8.GetBytes(_secret); + + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new[] + { + new Claim(ClaimTypes.PrimarySid, user.Id.ToString()), + new Claim(ClaimTypes.Email, user.Email), + new Claim(ClaimTypes.Name, user.DisplayName), + new Claim(ESuiteClaimTypes.DomainId, user.Domain.Id.ToString()), + //todo remove this from the token, and make it a separate call, so that I can keep the token small and keep the application running fast + new Claim(ESuiteClaimTypes.SecurityPrivileges, GetSecurityPrivileges(user)) + }), + + Expires = DateTime.UtcNow.AddMinutes(double.Parse(_expDate)), + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature), + Audience = _audience, + Issuer = _issuer + }; + + var token = tokenHandler.CreateToken(tokenDescriptor); + + return tokenHandler.WriteToken(token); + + } + + private string GetSecurityPrivileges(User user) + { + var myUserAccess = _roleManager.GetMyUserAccess(user); + var myUserPrivileges = myUserAccess.Select(x => x.SecurityAccess.ToString()); + return myUserPrivileges.ToJson(false); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/UserManager.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/UserManager.cs new file mode 100644 index 0000000..eb4340d --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/UserManager.cs @@ -0,0 +1,822 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.extensions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using e_suite.Database.Core.Tables.UserManager; +using e_suite.Modules.UserManager.Facade; +using e_suite.Modules.UserManager.Services; +using e_suite.Nuget.PasswordHasher; +using e_suite.Utilities.Pagination; +using eSuite.Core.Clock; +using eSuite.Core.MailService; +using eSuite.Core.Miscellaneous; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; +using System.ComponentModel.DataAnnotations; +using System.Linq.Expressions; +using System.Text; +using System.Text.Json; +using e_suite.Modules.UserManager.Extensions; +using IUserManager = e_suite.API.Common.IUserManager; +using System.Threading; +using System.Data; + +namespace e_suite.Modules.UserManager; + +public partial class UserManager : IUserManager +{ + private readonly IConfiguration _configuration; + private readonly IPasswordHasher _passwordHasher; + private readonly ITwoFactorAuthenticator _twoFactorAuthenticator; + private readonly IJwtService _jwtService; + private readonly IMailService _mailService; + private readonly IRandomNumberGenerator _randomNumberGenerator; + private readonly IClock _clock; + + private readonly IUserManagerRepository _userManagerRepository; + private readonly IDomainRepository _domainRepository; + + public UserManager(IConfiguration configuration, IPasswordHasher passwordHasher, ITwoFactorAuthenticator twoFactorAuthenticator, IJwtService jwtService, IMailService mailService, IRandomNumberGenerator randomNumberGenerator, IClock clock, IUserManagerRepository userManagerRepository, IDomainRepository domainRepository) + { + _configuration = configuration; + _passwordHasher = passwordHasher; + _twoFactorAuthenticator = twoFactorAuthenticator; + _jwtService = jwtService; + _mailService = mailService; + _randomNumberGenerator = randomNumberGenerator; + _clock = clock; + _userManagerRepository = userManagerRepository; + _domainRepository = domainRepository; + } + + private void HashPassword(User user, string password) + { + user.Password = _passwordHasher.HashPassword(user, password); + } + + private string GetEmailUserActionUrl(User existingUser, EmailUserAction emailConfirmation) + { + var emailToConfirmationToken = new EmailActionToken + { + Email = existingUser.Email, + EmailActionType = emailConfirmation.EmailActionType, + Token = emailConfirmation.Token + }; + + var jsonString = JsonSerializer.Serialize(emailToConfirmationToken); + var encodedBase64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonString)); + + var baseUrl = _configuration.GetConfigValue("BASE_URL", "baseUrl", "http://localhost:3000"); + var confirmEmail = $"{baseUrl?.Trim().TrimEnd('/')}/emailuseraction/{encodedBase64String}"; + return confirmEmail; + } + + private async Task SendEmailUserAction(AuditUserDetails auditUserDetails, User user, EmailUserActionType type, + CancellationToken cancellationToken) + { + if (user == null) + throw new Exception("User not found"); + + if (!user.Active) + throw new NotFoundException("Active User not found"); + + var emailUserAction = await CreateEmailUserAction(auditUserDetails, user, type, cancellationToken); + var emailUserActionUrl = GetEmailUserActionUrl(user, emailUserAction); + await SentEmailRequest(user, emailUserActionUrl, type, cancellationToken); + } + + private async Task CreateEmailUserAction(AuditUserDetails auditUserDetails, User existingUser, + EmailUserActionType type, CancellationToken cancellationToken) + { + var emailTimeout = GetEmailTimeoutHours(); + + var emailConfirmation = new EmailUserAction + { + Created = _clock.GetNow, + Expires = _clock.GetNow.AddHours(emailTimeout), + EmailActionType = type, + Token = Guid.NewGuid(), + UserId = existingUser.Id + }; + + await _userManagerRepository.AddEmailUserAction(auditUserDetails, emailConfirmation, cancellationToken); + return emailConfirmation; + } + + private int GetEmailTimeoutHours() + { + return _configuration.GetValue("Smtp:EmailTimeoutHours", 48); + } + + private async Task SentEmailRequest(User user, string emailUserActionUrl, EmailUserActionType type, CancellationToken cancellationToken) + { + var emailRequest = new MailRequest(); + emailRequest.To.Add(user); + emailRequest.EmailType = GetMailType(type); + emailRequest.Parameters.Add("url", emailUserActionUrl); + + await _mailService.RequestEMailAsync(emailRequest, cancellationToken); + } + + private async Task SendEmailRequest(User user, MailType mailType, CancellationToken cancellationToken) + { + var emailRequest = new MailRequest(); + emailRequest.To.Add(user); + emailRequest.EmailType = mailType; + + await _mailService.RequestEMailAsync(emailRequest, cancellationToken); + } + + private static MailType GetMailType(EmailUserActionType type) + { + return type switch + { + EmailUserActionType.ConfirmEmailAddress => MailType.ConfirmEmailAddress, + EmailUserActionType.DisableAuthenticator => MailType.DisableAuthenticator, + EmailUserActionType.PasswordReset => MailType.PasswordReset, + _ => throw new ArgumentException(message: $"{type} cannot be translated to and EmailType.", paramName: nameof(type)) + }; + } + + public async Task Login(Login userLogin, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserByEmail(userLogin.Email, cancellationToken); + + if (user == null) + { + return new LoginResponse + { + Result = LoginResult.Failed + }; + } + + var result = _passwordHasher.VerifyHashedPassword(user, user.Password, userLogin.Password); + + if (result == PasswordVerificationResult.Failed) + { + return new LoginResponse + { + Result = LoginResult.Failed + }; + } + + var auditUserDetails = new AuditUserDetails + { + UserId = user.Id, + UserDisplayName = user.DisplayName + }; + + if (result == PasswordVerificationResult.SuccessRehashNeeded) + { + HashPassword(user, userLogin.Password); + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + } + + if (userLogin.RequestTfaRemoval) + { + await SendEmailUserAction(auditUserDetails, user, EmailUserActionType.DisableAuthenticator, cancellationToken); + + return new LoginResponse + { + Result = LoginResult.TwoFactorAuthenticationRemovalRequested + }; + } + + if (user.UsingTwoFactorAuthentication) + { + if (string.IsNullOrWhiteSpace(userLogin.SecurityCode)) + { + return new LoginResponse + { + Result = LoginResult.TwoFactorAuthenticationCodeRequired + }; + } + + var tfaResult = + _twoFactorAuthenticator.ValidateTwoFactorPIN(user.TwoFactorAuthenticationKey, userLogin.SecurityCode); + + if (!tfaResult) + { + return new LoginResponse + { + Result = LoginResult.TwoFactorAuthenticationCodeIncorrect + }; + } + } + + return CreateLoginResponse(user); + } + public async Task LoginSso(long ssoId, string ssoUserId, CancellationToken cancellationToken = default!) + { + var user = await _userManagerRepository.GetUserSsoId(ssoId, ssoUserId, cancellationToken) ?? await _userManagerRepository.GetUserByDomainSsoId(ssoId, ssoUserId, cancellationToken); + + return CreateLoginResponse(user); + } + + private LoginResponse CreateLoginResponse(User? user) + { + if (user == null) + { + return new LoginResponse + { + Result = LoginResult.Failed + }; + } + + if (!user.Active) + { + return new LoginResponse + { + Result = LoginResult.Failed + }; + } + + if (!user.EmailConfirmed) + { + return new LoginResponse + { + Result = LoginResult.EmailNotConfirmed + }; + } + + var token = _jwtService.GenerateSecurityToken(user); + return new LoginResponse + { + Result = LoginResult.Success, + Token = token + }; + } + + public async Task CreateUser(AuditUserDetails auditUserDetails, UserRegistration userRegistration, CancellationToken cancellationToken) + { + await _userManagerRepository.TransactionAsync(async () => + { + userRegistration.Email = userRegistration.Email.Trim(); + ValidateEmail(userRegistration.Email); + await CheckForExistingUserByEmail(userRegistration.Email, cancellationToken); + + var currentUser = await _userManagerRepository.GetUserById(new GeneralIdRef + { + Id = auditUserDetails.UserId + }, cancellationToken); + + var domainId = currentUser!.DomainId; + if (userRegistration.DomainId != null ) + { + var domain = await _userManagerRepository.GetDomainById(userRegistration.DomainId, cancellationToken) + ?? throw new NotFoundException("unable to find domain"); + domainId = domain.Id; + } + + var user = new User + { + FirstName = userRegistration.FirstName.Trim(), + MiddleNames = userRegistration.MiddleNames.Trim(), + LastName = userRegistration.LastName.Trim(), + Email = userRegistration.Email, + EmailConfirmed = false, + DomainId = domainId + }; + + DisableTwoFactorAuthenticationForUser(user); + + var password = _randomNumberGenerator.GetRandomString(10); + + HashPassword(user, password); + + await _userManagerRepository.AddUser(auditUserDetails, user, cancellationToken); + + await SendEmailUserAction(auditUserDetails, user, EmailUserActionType.ConfirmEmailAddress, cancellationToken); + }); + } + + private async Task CheckForExistingUserByEmail(string emailAddress, CancellationToken cancellationToken) + { + var existingUser = await _userManagerRepository.GetUserByEmail(emailAddress, cancellationToken); + if (existingUser != null) + throw new ExistsException("User Already Exists"); + } + + private static void ValidateEmail(string email) + { + if (!(new EmailAddressAttribute()).IsValid(email)) + throw new ArgumentException($"{email} is not a valid email address"); + } + + private void DisableTwoFactorAuthenticationForUser(User user) + { + user.UsingTwoFactorAuthentication = false; + user.TwoFactorAuthenticationKey = GenerateTwoFactorAuthenticationKey(); + } + + private string GenerateTwoFactorAuthenticationKey() + { + return _randomNumberGenerator.GetRandomString(_configuration.GetValue("twoFactorAuthentication:keySize")); + } + + public async Task RefreshToken(string email, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserByEmail(email, cancellationToken); + return RefreshToken(user); + } + + public async Task RefreshToken(IGeneralIdRef id, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserById(id, cancellationToken); + return RefreshToken(user); + } + + private LoginResponse RefreshToken(User? user) + { + return CreateLoginResponse(user); + } + + public async Task ForgotPassword(string email, CancellationToken cancellationToken) + { + await _userManagerRepository.TransactionAsync( async () => + { + var user = await GetUserByEmailAsync(email, cancellationToken); + + if (!user.EmailConfirmed) { + throw new EmailNotConfirmedException("Email not confirmed"); + } + + var auditUserDetails = new AuditUserDetails + { + UserId = user.Id, + UserDisplayName = user.DisplayName + }; + + await SendEmailUserAction(auditUserDetails, user, EmailUserActionType.PasswordReset, cancellationToken); + }); + } + + public async Task CompleteEmailAction(EmailActionToken token, CancellationToken cancellationToken) + { + return await _userManagerRepository.TransactionAsync(async () => + { + var emailUserAction = await _userManagerRepository.GetEmailUserAction(token.Token, cancellationToken) + ?? throw new TokenInvalidException("Your email token is invalid"); + + if ((emailUserAction.EmailActionType == EmailUserActionType.ConfirmEmailAddress || + emailUserAction.EmailActionType == EmailUserActionType.PasswordReset)) + CheckPasswordStrength(token.Password); + + var user = emailUserAction.User; + + if (!user.Email.Equals(token.Email, StringComparison.CurrentCultureIgnoreCase)) + throw new InvalidEmailException("Your email is invalid"); + + switch (emailUserAction.EmailActionType) + { + case EmailUserActionType.ConfirmEmailAddress: + throw new ArgumentException($"EmailActionType {emailUserAction.EmailActionType} not supported, use the UI instead."); + case EmailUserActionType.DisableAuthenticator: + DisableTwoFactorAuthenticationForUser(user); + break; + case EmailUserActionType.PasswordReset: + AddPasswordHash(user,token.Password); + break; + default: + throw new ArgumentException($"EmailActionType {emailUserAction.EmailActionType} not implemented"); + } + + var auditUserDetails = new AuditUserDetails + { + UserId = user.Id, + UserDisplayName = user.DisplayName + }; + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + + await _userManagerRepository.DeleteEmailUserAction(auditUserDetails, emailUserAction, cancellationToken); + + if (emailUserAction.EmailActionType == EmailUserActionType.PasswordReset) { + await SendEmailRequest(user, MailType.PasswordResetCompleted, cancellationToken); + } + return user; + }); + } + + public async Task DeactivateUser(AuditUserDetails auditUserDetails, string email, CancellationToken cancellationToken) + { + await _userManagerRepository.TransactionAsync( async () => + { + var user = await GetUserByEmailAsync(email, cancellationToken); + + await DeactivateUser(auditUserDetails, user, cancellationToken); + }); + } + + public async Task DeactivateUser(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + await _userManagerRepository.TransactionAsync(async () => + { + var user = await _userManagerRepository.GetUserById(generalIdRef, cancellationToken) + ?? throw new NotFoundException("Unable to find user"); + + await DeactivateUser(auditUserDetails, user, cancellationToken); + }); + } + + private async Task DeactivateUser(AuditUserDetails auditUserDetails, User user, CancellationToken cancellationToken) + { + if (!user.Active) + throw new InvalidOperationException("User already deactivated"); + + if (user.Id == auditUserDetails.UserId) + throw new InvalidOperationException("You can't delete yourself"); + + user.Active = false; + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + } + + public async Task GetProfile(string email, CancellationToken cancellationToken) + { + var applicationName = _configuration.GetValue("applicationName"); + + if (string.IsNullOrWhiteSpace(applicationName)) + { + throw new SystemException("applicationName has not been set"); + } + + var user = await GetUserByEmailAsync(email, cancellationToken); + + var setupInfo = _twoFactorAuthenticator.GenerateSetupCode(applicationName, user.Email, user.TwoFactorAuthenticationKey, false); + + var twoFactorAuthenticationSettings = new TwoFactorAuthenticationSettings + { + QrCodeImageUrl = setupInfo.QrCodeSetupImageUrl, + ManualEntrySetupCode = setupInfo.ManualEntryKey + }; + + var ssoProviders = GetSsoProvidersForUser(); + + var userProfile = new UserProfile + { + FirstName = user.FirstName, + MiddleNames = user.MiddleNames, + LastName = user.LastName, + Email = user.Email, + UsingTwoFactorAuthentication = user.UsingTwoFactorAuthentication, + TwoFactorAuthenticationSettings = twoFactorAuthenticationSettings, + Created = user.Created, + DomainSsoProviderId = user.Domain.SsoProviderId, + SsoProviderId = user.SsoProviderId, + SsoSubject = user.SsoSubject, + SsoProviders = ssoProviders + .ToDictionary(x => x.Id, x => x.Name) + }; + + return userProfile; + } + + private IEnumerable GetSsoProvidersForUser() + { + var ssoProviders = _userManagerRepository.GetSsoProviders().Where(x => x.Deleted == false && x.IsPublic == true); + + return ssoProviders; + } + + public async Task UpdateProfile(AuditUserDetails auditUserDetails, string email, UpdatedUserProfile userProfile, CancellationToken cancellationToken) + { + await _userManagerRepository.TransactionAsync(async () => + { + var user = await GetUserByEmailAsync(email, cancellationToken); + userProfile.Email = userProfile.Email.Trim(); + + if (!string.IsNullOrWhiteSpace(userProfile.Email)) + { + ValidateEmail(userProfile.Email); + + if (user.Email != userProfile.Email) + { + await CheckForExistingUserByEmail(userProfile.Email, cancellationToken); + user.EmailConfirmed = false; + user.Email = userProfile.Email; + } + } + + user.FirstName = userProfile.FirstName; + user.MiddleNames = userProfile.MiddleNames; + user.LastName = userProfile.LastName; + user.Email = userProfile.Email; + + await SetInternalAuthenticationDetails(user, userProfile, true, cancellationToken); + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + + if (!user.EmailConfirmed) + { + await SendEmailUserAction(auditUserDetails, user, EmailUserActionType.ConfirmEmailAddress, cancellationToken); + } + }); + } + + private async Task SetInternalAuthenticationDetails( + User user, + UpdatedUserProfile userProfile, + bool sendEmail, + CancellationToken cancellationToken + ) + { + if (!string.IsNullOrWhiteSpace(userProfile.Password)) + { + HashPassword(user, userProfile.Password); + if (sendEmail) + await SendEmailRequest(user, MailType.PasswordResetCompleted, cancellationToken); + } + + if (userProfile.UsingTwoFactorAuthentication != user.UsingTwoFactorAuthentication) + { + if (userProfile.UsingTwoFactorAuthentication) + { + if (!string.IsNullOrWhiteSpace(userProfile.SecurityCode)) + { + if (_twoFactorAuthenticator.ValidateTwoFactorPIN(user.TwoFactorAuthenticationKey, + userProfile.SecurityCode)) + user.UsingTwoFactorAuthentication = true; + } + } + else + DisableTwoFactorAuthenticationForUser(user); + } + } + + public async Task EditUser(AuditUserDetails auditUserDetails, EditUser user, CancellationToken cancellationToken) + { + await _userManagerRepository.TransactionAsync(async () => + { + var editUser = await _userManagerRepository.GetUserById(user.Id! , cancellationToken) + ?? throw new NotFoundException("unable to find user"); + + if (!editUser.Active) + throw new DeletedRowInaccessibleException("This user is inactive so cannot be modified. You will need to create the user again."); + + var userDomain = await _userManagerRepository.GetDomainById(user.Domain, cancellationToken) + ?? throw new NotFoundException("unable to find domain"); + + editUser.FirstName = user.FirstName; + editUser.MiddleNames = user.MiddleNames; + editUser.LastName = user.LastName; + editUser.Email = user.Email; + editUser.DomainId = userDomain.Id; + editUser.Domain = userDomain; + + await _userManagerRepository.EditUser(auditUserDetails, editUser, cancellationToken); + }); + } + + public async Task> GetUsersAsync(Paging paging, CancellationToken cancellationToken) + { + var users = _userManagerRepository.GetUsers().Where(x => x.Active == true); + + var paginatedData = await PaginatedData.Paginate(users, paging, KeySelector, FilterSelector, cancellationToken); + + var paginatedResult = new PaginatedData + { + Count = paginatedData.Count, + Page = paginatedData.Page, + PageSize = paginatedData.PageSize, + Data = paginatedData.Data.Select(MapUser) + }; + return paginatedResult; + } + + public async Task GetUserAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserById(generalIdRef, cancellationToken) + ?? throw new NotFoundException("User not found"); + + return MapUser(user); + } + + public async Task GetUserByEmailAsync(string email, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserByEmail(email, cancellationToken) + ?? throw new NotFoundException("User not found"); + + return user; + } + + private GetUser MapUser(User user) + { + var getUser = new GetUser + { + Id = user.Id, + Guid = user.Guid, + FirstName = user.FirstName, + LastName = user.LastName, + MiddleNames = user.MiddleNames, + DisplayName = user.DisplayName, + Email = user.Email, + Created = user.Created, + LastUpdated = user.LastUpdated, + Domain = new GeneralIdRef + { + Id = user.Domain.Id, + Guid = user.Domain.Guid + }, + DomainName = user.Domain.Name, + EmailConfirmed = user.EmailConfirmed + }; + + return getUser; + } + + private Expression> FilterSelector(string? key, string value) + { + return key?.ToLowerInvariant() switch + { + "firstname" => x => x.FirstName.Contains(value), + "lastname" => x => x.LastName.Contains(value), + "middlenames" => x => x.MiddleNames.Contains(value), + "displayname" => x => ( x.FirstName + " " + x.MiddleNames + " " + x.LastName ).Contains(value), + "domainname" => x => x.Domain.Name.Contains(value), + "created" => x => x.Created.ToString().Contains(value), + "lastupdated" => x => x.LastUpdated.ToString().Contains(value), + "email" => x => x.Email.Contains(value), + _ => x => x.Email.Contains(value) + }; + } + + private Expression> KeySelector(string? sortKey) + { + return sortKey?.ToLowerInvariant() switch + { + "firstname" => x => x.FirstName, + "lastname" => x => x.LastName, + "middlenames" => x => x.MiddleNames, + "displayname" => x => x.FirstName + " " + x.MiddleNames + " " + x.LastName, + "domainname" => x => x.Domain.Name, + "created" => x => x.Created, + "lastupdated" => x => x.LastUpdated, + "email" => x => x.Email, + _ => x => x.Email + }; + } + + private void AddPasswordHash(User user,string tokenPass) + { + if (string.IsNullOrWhiteSpace(tokenPass)) + throw new ArgumentException("Invalid password supplied"); + HashPassword(user, tokenPass); + } + + private static void CheckPasswordStrength(string password) + { + const int minPasswordLength = 12; + const string symbols = "~`! @#$%^&*()_+={[}|\\:;\"'<,->.?/"; + + if (password.Length < minPasswordLength) + throw new WeakPasswordException($"Password must be at least {minPasswordLength} characters"); + + if (!password.Contains(symbols.ToCharArray())) + throw new WeakPasswordException($"Password must contain at least one symbol: {symbols}"); + + if (!password.Any(char.IsDigit)) + throw new WeakPasswordException($"Password must contain at least one number"); + + if (!password.Any(char.IsUpper)) + throw new WeakPasswordException($"Password must contain at least one upper case character"); + + if (!password.Any(char.IsLower)) + throw new WeakPasswordException($"Password must contain at least one lower case character"); + } + + public async Task ResendConfirmEmail( + AuditUserDetails auditUserDetails, + GeneralIdRef generalIdRef, + CancellationToken cancellationToken + ) + { + var user = await _userManagerRepository.GetUserById(generalIdRef, cancellationToken) + ?? throw new NotFoundException("User not found"); + + await SendEmailUserAction(auditUserDetails, user, EmailUserActionType.ConfirmEmailAddress, cancellationToken); + } + + public async Task GetCurrentEmailActionUrl( string emailAddress, EmailUserActionType emailUserActionType, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserByEmail(emailAddress, cancellationToken) + ?? throw new NotFoundException("User not found"); + var emailUserAction = await _userManagerRepository.GetCurrentEmailUserAction(user.Id, emailUserActionType, cancellationToken) + ?? throw new NotFoundException("Email action not found"); + var emailUserActionUrl = GetEmailUserActionUrl(user, emailUserAction); + return emailUserActionUrl; + } + + public async Task GetSsoProviderForEmail(string loginEmail, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserByEmail(loginEmail, cancellationToken); + + if (user?.DomainId != null) + { + var domain = + await _domainRepository.GetDomainById(new GeneralIdRef { Id = user.DomainId }, cancellationToken); + + if (domain?.SsoProvider != null) + return domain.SsoProvider; + } + + return user?.SsoProvider; + } + + public async Task GetSsoProviderById(long ssoProviderId, CancellationToken cancellationToken) + { + var ssoProvider = await _userManagerRepository.GetSsoProviderById(ssoProviderId, cancellationToken); + return ssoProvider; + } + + public async Task LinkSsoProfileToUser(AuditUserDetails auditUserDetails, User user, long ssoId, string ssoUserId, bool setEmailConfirmed, CancellationToken cancellationToken) + { + if (user == null) + throw new NullReferenceException(); + + + if (user.Domain.SsoProviderId == null) + { + var ssoProvider = await _userManagerRepository.GetSsoProviderById(ssoId, cancellationToken) ?? throw new NotFoundException("SSO Provider not found"); + + user.SsoProviderId = ssoProvider.Id; + } + user.SsoSubject = ssoUserId; + + if (setEmailConfirmed) + user.EmailConfirmed = true; + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + } + + public async Task TurnOfSsoForUser(AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserById(generalIdRef, cancellationToken) ?? throw new NotFoundException("User not found"); + + user.SsoProviderId = null; + user.SsoSubject = string.Empty; + user.SsoProvider = null; + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + } + + public async Task CreateSingleUseGuid( + AuditUserDetails auditUserDetails, + GeneralIdRef generalIdRef, + CancellationToken cancellationToken + ) + { + var user = await _userManagerRepository.GetUserById(generalIdRef, cancellationToken) ?? throw new NotFoundException("User not found"); + + var singleUseGuid = new SingleUseGuid + { + UserId = user.Id, + User = user, + Guid = Guid.NewGuid(), + Expires = _clock.GetNow.AddHours(GetEmailTimeoutHours()) + }; + + await _userManagerRepository.SaveSingleUseGuidForUser(singleUseGuid, cancellationToken); + + return singleUseGuid.Guid; + } + + public async Task GetUserWithSingleUseGuid(Guid guid, CancellationToken cancellationToken) + { + var user = await _userManagerRepository.GetUserBySingleUseGuid(guid, cancellationToken); + + await _userManagerRepository.DeleteSingleUseGuid(guid, cancellationToken); + return user; + } + + public async Task SetAuthentication( + AuditUserDetails auditUserDetails, + UserAuthenticationDetails userAuthenticationDetails, + bool setEmailConfirmed, + CancellationToken cancellationToken + ) + { + await _userManagerRepository.TransactionAsync(async () => + { + var user = await _userManagerRepository.GetUserById(userAuthenticationDetails.Id, cancellationToken) + ?? throw new NotFoundException("User not found"); + + var userProfile = new UpdatedUserProfile + { + Password = userAuthenticationDetails.Password, + SecurityCode = userAuthenticationDetails.SecurityCode, + UsingTwoFactorAuthentication = userAuthenticationDetails.UsingTwoFactorAuthentication + }; + + await SetInternalAuthenticationDetails(user, userProfile, false, cancellationToken); + + if (setEmailConfirmed) + user.EmailConfirmed = true; + + await _userManagerRepository.EditUser(auditUserDetails, user, cancellationToken); + }); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/UserManagerMaintenance.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/UserManagerMaintenance.cs new file mode 100644 index 0000000..06cc5e6 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/UserManagerMaintenance.cs @@ -0,0 +1,25 @@ +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Modules.UserManager.Repository; + +namespace e_suite.Modules.UserManager; + +public class UserManagerMaintenance : IUserManagerMaintenance +{ + private readonly IUserManagerRepository _userManagerRepository; + + public UserManagerMaintenance(IUserManagerRepository userManagerRepository) + { + _userManagerRepository = userManagerRepository; + } + + public async Task ClearOldEmailActions() + { + await _userManagerRepository.DeleteExpiredEmailUserActions(); + } + + public async Task ClearOldSingleUserGuids() + { + await _userManagerRepository.DeleteExpiredSingleUseGuids(); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Utils/Base32.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Utils/Base32.cs new file mode 100644 index 0000000..69dcefb --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Utils/Base32.cs @@ -0,0 +1,154 @@ +/* + * Derived from https://github.com/google/google-authenticator-android/blob/master/AuthenticatorApp/src/main/java/com/google/android/apps/authenticator/Base32String.java + * + * Copyright (C) 2016 BravoTango86 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Text; +using System.Text.RegularExpressions; + +namespace e_suite.Modules.UserManager.Utils; + +public static class Base32 +{ + + private static readonly char[] Digits; + private static readonly int Mask; + private static readonly int Shift; + private static readonly Dictionary CharMap = new(); + private const string Separator = "-"; + + static Base32() + { + Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray(); + Mask = Digits.Length - 1; + Shift = NumberOfTrailingZeros(Digits.Length); + for (int i = 0; i < Digits.Length; i++) CharMap[Digits[i]] = i; + } + + private static int NumberOfTrailingZeros(int i) + { + // HD, Figure 5-14 + int y; + if (i == 0) return 32; + int n = 31; + y = i << 16; if (y != 0) { n -= 16; i = y; } + y = i << 8; if (y != 0) { n -= 8; i = y; } + y = i << 4; if (y != 0) { n -= 4; i = y; } + y = i << 2; if (y != 0) { n -= 2; i = y; } + return n - (int)((uint)(i << 1) >> 31); + } + + public static byte[] Decode(string encoded) + { + // Remove whitespace and separators + encoded = encoded.Trim().Replace(Separator, ""); + + // Remove padding. Note: the padding is used as hint to determine how many + // bits to decode from the last incomplete chunk (which is commented out + // below, so this may have been wrong to start with). + encoded = Regex.Replace(encoded, "[=]*$", ""); + + // Canonicalize to all upper case + encoded = encoded.ToUpper(); + if (encoded.Length == 0) + { + return Array.Empty(); + } + int encodedLength = encoded.Length; + int outLength = encodedLength * Shift / 8; + byte[] result = new byte[outLength]; + int buffer = 0; + int next = 0; + int bitsLeft = 0; + foreach (char c in encoded) + { + if (!CharMap.ContainsKey(c)) + { + throw new DecodingException("Illegal character: " + c); + } + buffer <<= Shift; + buffer |= CharMap[c] & Mask; + bitsLeft += Shift; + if (bitsLeft >= 8) + { + result[next++] = (byte)(buffer >> (bitsLeft - 8)); + bitsLeft -= 8; + } + } + // We'll ignore leftover bits for now. + // + // if (next != outLength || bitsLeft >= SHIFT) { + // throw new DecodingException("Bits left: " + bitsLeft); + // } + return result; + } + + + public static string Encode(byte[] data, bool padOutput = false) + { + switch (data.Length) + { + case 0: + return ""; + // SHIFT is the number of bits per output character, so the length of the + // output is the length of the input multiplied by 8/SHIFT, rounded up. + case >= 1 << 28: + // The computation below will fail, so don't do it. + throw new ArgumentOutOfRangeException(nameof(data)); + } + + var outputLength = (data.Length * 8 + Shift - 1) / Shift; + StringBuilder result = new(outputLength); + + int buffer = data[0]; + int next = 1; + int bitsLeft = 8; + while (bitsLeft > 0 || next < data.Length) + { + if (bitsLeft < Shift) + { + if (next < data.Length) + { + buffer <<= 8; + buffer |= (data[next++] & 0xff); + bitsLeft += 8; + } + else + { + int pad = Shift - bitsLeft; + buffer <<= pad; + bitsLeft += pad; + } + } + int index = Mask & (buffer >> (bitsLeft - Shift)); + bitsLeft -= Shift; + result.Append(Digits[index]); + } + if (padOutput) + { + int padding = 8 - (result.Length % 8); + if (padding > 0) result.Append(new string('=', padding == 8 ? 0 : padding)); + } + return result.ToString(); + } + + private class DecodingException : Exception + { + public DecodingException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Utils/ObjectExtensions.cs b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Utils/ObjectExtensions.cs new file mode 100644 index 0000000..2053173 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/Utils/ObjectExtensions.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; +using System.Text.Json; + +namespace e_suite.Modules.UserManager.Utils; +public static class ObjectExtensions +{ + /// + /// Serialize the current object to Json + /// + /// + /// + public static string ToJson(this object value, bool writeIndented = true) + { + var options = new JsonSerializerOptions + { + WriteIndented = writeIndented, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + return JsonSerializer.Serialize(value, options); + } +} \ No newline at end of file diff --git a/e-suite.Modules.UserManager/e-suite.Modules.UserManager/e-suite.Modules.UserManager.csproj b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/e-suite.Modules.UserManager.csproj new file mode 100644 index 0000000..510bce0 --- /dev/null +++ b/e-suite.Modules.UserManager/e-suite.Modules.UserManager/e-suite.Modules.UserManager.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + e_suite.Modules.UserManager + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Modules.UserManager/nuget.config b/e-suite.Modules.UserManager/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Modules.UserManager/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/.gitattributes b/e-suite.Nuget.PasswordHasher/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/.gitignore b/e-suite.Nuget.PasswordHasher/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Nuget.PasswordHasher/.runsettings b/e-suite.Nuget.PasswordHasher/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/README.md b/e-suite.Nuget.PasswordHasher/README.md new file mode 100644 index 0000000..7460171 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/README.md @@ -0,0 +1,22 @@ +# Introduction +Custom password hashing methods for .net. +This adds support for Salted and Peppered passwords, using SHA512 hashing. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +Open the e-suite.Nuget.PasswordHasher.sln. +NUnit unit testing is provided. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/azure-pipelines.yml b/e-suite.Nuget.PasswordHasher/azure-pipelines.yml new file mode 100644 index 0000000..ad9d44d --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/ByteArrayExtensionsTests.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/ByteArrayExtensionsTests.cs new file mode 100644 index 0000000..8f6c475 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/ByteArrayExtensionsTests.cs @@ -0,0 +1,38 @@ +using NUnit.Framework; + +namespace e_suite.Nuget.PasswordHasher.UnitTests; + +[TestFixture] +public class ByteArrayExtensionsTests +{ + [Test] + public void Concatenate_ReturnsExpectedResult() + { + //Arrange + var expectedResult = new byte[6]; + expectedResult[0] = 0; + expectedResult[1] = 1; + expectedResult[2] = 2; + expectedResult[3] = 3; + expectedResult[4] = 4; + expectedResult[5] = 5; + + var array1 = new byte[3]; + array1[0] = 0; + array1[1] = 1; + array1[2] = 2; + + var array2 = new byte[3]; + array2[0] = 3; + array2[1] = 4; + array2[2] = 5; + + //Act + var actualResult = array1.Concatenate(array2); + + //Assert + Assert.That(actualResult.Length, Is.EqualTo(expectedResult.Length)); + for (var i = 0; i < actualResult.Length; i++) + Assert.That(actualResult[i], Is.EqualTo(expectedResult[i])); + } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/CustomPasswordHasherUnitTests.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/CustomPasswordHasherUnitTests.cs new file mode 100644 index 0000000..5e1a298 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/CustomPasswordHasherUnitTests.cs @@ -0,0 +1,238 @@ +using System.Text; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using NUnit.Framework; + +namespace e_suite.Nuget.PasswordHasher.UnitTests; + +[TestFixture] +public class CustomPasswordHasherUnitTests +{ + public class User + { + public string Password = string.Empty; + } + + private CustomPasswordHasher _passwordHasher = null!; + private CustomPasswordHasher _passwordHasherFormulaTwo = null!; + + public class Options : IOptions where TOptions : class, new() + { + public TOptions Value { get; } = new TOptions(); + } + + [SetUp] + public void Setup() + { + _passwordHasher = new CustomPasswordHasher(); + + var options = new Options + { + Value = + { + CompatibilityMode = CustomPasswordHasherMethod.formulaTwo + } + }; + + _passwordHasherFormulaTwo = new CustomPasswordHasher(options); + } + + [Test] + public void HashPassword_WhenHashingPassword_EnsuresNewSaltedHash() + { + //Arrange + var user = new User(); + var password = "12345"; + + //Act + var result = _passwordHasher.HashPassword(user, password); + var result2 = _passwordHasher.HashPassword(user, password); + + //Assert + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.EqualTo(string.Empty)); + Assert.That(result, Is.Not.EqualTo(password)); + Assert.That(result, Is.Not.EqualTo(result2)); + } + + + [Test] + public void VerifyingPassword_PasswordEmpty_ReturnsFailed() + { + //Arrange + var user = new User + { + Password = "" + }; + var password = "12345"; + + //Act + var result = _passwordHasher.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo( PasswordVerificationResult.Failed)); + } + + [Test] + public void VerifyingPassword_PasswordCorrect_ReturnsSuccess() + { + //Arrange + var user = new User + { + Password = "AgAAAAIAACcQAAAAAAAAABBgrjKk7U86gEbFKXkU83K95YntV93+eyArPbnMVI6vLyrLL9IhaqZmoo64aAU0zKqhecnuOG2eO4XtHP2kz3RabjvbUSfHBMiP6O1F/DIq1Q==" + }; + var password = "12345"; + + //Act + var result = _passwordHasher.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.Success)); + } + + [Test] + public void VerifyingPassword_PasswordInCorrect_ReturnsFailed() + { + //Arrange + var user = new User + { + Password = "AgAAAAIAACcQAAAAAAAAABBgrjKk7U86gEbFKXkU83K95YntV93+eyArPbnMVI6vLyrLL9IhaqZmoo64aAU0zKqhecnuOG2eO4XtHP2kz3RabjvbUSfHBMiP6O1F/DIq1Q==" + }; + var password = "ThisWillNeverWork"; + + //Act + var result = _passwordHasher.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.Failed)); + } + + [Test] + public void VerifyingPassword_CorrectPasswordUsingOldAlgorithm_ReturnsSuccessRehashNeeded() + { + //Arrange + var user = new User + { + Password = "" + }; + var password = "12345"; + + user.Password = _passwordHasherFormulaTwo.HashPassword(user, password); + + //Act + var result = _passwordHasher.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.SuccessRehashNeeded)); + } + + [Test] + public void VerifyingPassword_WhenPepperPresent_ReturnsSuccess() + { + //Arrange + var options = new Options(); + options.Value.PepperDictionary.Add(1, Encoding.ASCII.GetBytes("MyPepper")); + + var localPasswordHasher = new CustomPasswordHasher(options); + + var user = new User + { + Password = "" + }; + var password = "12345"; + + + user.Password = localPasswordHasher.HashPassword(user, password); + + //Act + var result = localPasswordHasher.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.Success)); + } + + [Test] + public void VerifyingPassword_WhenPepperNewPepperAdded_ReturnsSuccess() + { + //Arrange + var options = new Options(); + options.Value.PepperDictionary.Add(1, Encoding.ASCII.GetBytes("MyPepper")); + + var localPasswordHasher = new CustomPasswordHasher(options); + + var user = new User + { + Password = "" + }; + var password = "12345"; + + user.Password = localPasswordHasher.HashPassword(user, password); + + options.Value.PepperDictionary.Add(2, Encoding.ASCII.GetBytes("NewPepper")); + + var localPasswordHasher2 = new CustomPasswordHasher(options); + + //Act + var result = localPasswordHasher2.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.Success)); + } + + [Test] + public void VerifyingPassword_WhenPepperNewPepperAddedFirst_ReturnsFailed() + { + //Arrange + var options = new Options(); + options.Value.PepperDictionary.Add(1, Encoding.ASCII.GetBytes("MyPepper")); + + var localPasswordHasher = new CustomPasswordHasher(options); + + var user = new User + { + Password = "" + }; + var password = "12345"; + + user.Password = localPasswordHasher.HashPassword(user, password); + + options.Value.PepperDictionary[1] = Encoding.ASCII.GetBytes("NewPepper"); + options.Value.PepperDictionary.Add(2, Encoding.ASCII.GetBytes("MyPepper")); + + var localPasswordHasher2 = new CustomPasswordHasher(options); + + //Act + var result = localPasswordHasher2.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.Failed)); + } + + [Test] + public void VerifyingPassword_WhenPepperDoesNotMatch_ReturnsFailed() + { + //Arrange + var options = new Options(); + options.Value.PepperDictionary.Add(1, Encoding.ASCII.GetBytes("MyPepper")); + + var localPasswordHasher = new CustomPasswordHasher(options); + + var user = new User + { + Password = "" + }; + var password = "12345"; + + user.Password = localPasswordHasher.HashPassword(user, password); + + options.Value.PepperDictionary[1] = Encoding.ASCII.GetBytes("NewPepper"); + + var localPasswordHasher2 = new CustomPasswordHasher(options); + + //Act + var result = localPasswordHasher2.VerifyHashedPassword(user, user.Password, password); + + //Assert + Assert.That(result, Is.EqualTo(PasswordVerificationResult.Failed)); + } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/e-suite.Nuget.PasswordHasher.UnitTests.csproj b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/e-suite.Nuget.PasswordHasher.UnitTests.csproj new file mode 100644 index 0000000..5d99cc0 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.UnitTests/e-suite.Nuget.PasswordHasher.UnitTests.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + e_suite.Nuget.PasswordHasher.UnitTests + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.sln b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.sln new file mode 100644 index 0000000..978e9fd --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Nuget.PasswordHasher", "e-suite.Nuget.PasswordHasher\e-suite.Nuget.PasswordHasher.csproj", "{D0D20A53-30B1-42D9-9089-0CA75AE75B76}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{58081958-4AA8-4EFF-908D-058DDC1A21C9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unit Tests", "Unit Tests", "{CB91AA11-F2F4-4F33-A939-3F915EA5400D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Nuget.PasswordHasher.UnitTests", "e-suite.Nuget.PasswordHasher.UnitTests\e-suite.Nuget.PasswordHasher.UnitTests.csproj", "{9E8027A5-3EFD-4431-B50D-5C1C8583BAF9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D0D20A53-30B1-42D9-9089-0CA75AE75B76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0D20A53-30B1-42D9-9089-0CA75AE75B76}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0D20A53-30B1-42D9-9089-0CA75AE75B76}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0D20A53-30B1-42D9-9089-0CA75AE75B76}.Release|Any CPU.Build.0 = Release|Any CPU + {9E8027A5-3EFD-4431-B50D-5C1C8583BAF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E8027A5-3EFD-4431-B50D-5C1C8583BAF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E8027A5-3EFD-4431-B50D-5C1C8583BAF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E8027A5-3EFD-4431-B50D-5C1C8583BAF9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {CB91AA11-F2F4-4F33-A939-3F915EA5400D} = {58081958-4AA8-4EFF-908D-058DDC1A21C9} + {9E8027A5-3EFD-4431-B50D-5C1C8583BAF9} = {CB91AA11-F2F4-4F33-A939-3F915EA5400D} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {825B8F7C-E7E7-4A36-B4D1-030B13F13636} + EndGlobalSection +EndGlobal diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/ByteArrayExtensions.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/ByteArrayExtensions.cs new file mode 100644 index 0000000..5ba2608 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/ByteArrayExtensions.cs @@ -0,0 +1,11 @@ +namespace e_suite.Nuget.PasswordHasher; +public static class ByteArrayExtensions +{ + public static byte[] Concatenate(this byte[] byteArray1, byte[] byteArray2) + { + byte[] saltAndPepper = new byte[byteArray1.Length + byteArray2.Length]; + Buffer.BlockCopy(byteArray1, 0, saltAndPepper, 0, byteArray1.Length); + Buffer.BlockCopy(byteArray2, 0, saltAndPepper, byteArray1.Length, byteArray2.Length); + return saltAndPepper; + } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasher.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasher.cs new file mode 100644 index 0000000..f0f6bc0 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasher.cs @@ -0,0 +1,426 @@ +using System.Security.Cryptography; +using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; + +namespace e_suite.Nuget.PasswordHasher; + +public class CustomPasswordHasher : IPasswordHasher where TUser : class +{ + // https://owasp.org/www-project-cheat-sheets/cheatsheets/Password_Storage_Cheat_Sheet.html + // default password hasher code is https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/PasswordHasher.cs + // it's already using SHA256 with properly salted passwords, so no need to reinvent the wheel here, and will be upgraded in future versions of .net core. + + /* ======================= + * HASHED PASSWORD FORMATS + * ======================= + * + * FormulaOne: + * PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations. + * (See also: SDL crypto guidelines v5.1, Part III) + * Format: { 0x00, salt, subkey } + * + * ForumulaTwo: + * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations. + * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey } + * (All UInt32s are stored big-endian.) + * + * ForumulaThree: + * PBKDF2 with HMAC-SHA512, 128-bit salt, 256-bit subkey, 10000 iterations. + * Format: { 0x01, prf (UInt32), iter count (UInt32), pepperIndex (UInt32), salt length (UInt32), salt, subkey } + * (All UInt32s are stored big-endian.) + */ + + private readonly CustomPasswordHasherMethod _compatibilityMode; + private readonly int _iterCount; + private readonly RandomNumberGenerator _rng; + private readonly Dictionary _pepper; + + /// + /// Creates a new instance of . + /// + /// The options for this instance. + public CustomPasswordHasher(IOptions optionsAccessor = null!) + { + var options = optionsAccessor?.Value ?? new CustomPasswordHasherOptions(); + _pepper = options.PepperDictionary; + + _compatibilityMode = options.CompatibilityMode; + switch (_compatibilityMode) + { + case CustomPasswordHasherMethod.formulaOne: + // nothing else to do + break; + + case CustomPasswordHasherMethod.formulaTwo: + _iterCount = options.IterationCount; + if (_iterCount < 1) + { + throw new InvalidOperationException(Resources.InvalidPasswordHasherIterationCount); + } + break; + + case CustomPasswordHasherMethod.formulaThree: + _iterCount = options.IterationCount; + if (_iterCount < 1) + { + throw new InvalidOperationException(Resources.InvalidPasswordHasherIterationCount); + } + + break; + default: + throw new InvalidOperationException(Resources.InvalidPasswordHasherCompatibilityMode); + } + + _rng = RandomNumberGenerator.Create(); + } + +#if NETSTANDARD2_0 + // Compares two byte arrays for equality. The method is specifically written so that the loop is not optimized. + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] + private static bool ByteArraysEqual(byte[] a, byte[] b) + { + if (a == null && b == null) + { + return true; + } + if (a == null || b == null || a.Length != b.Length) + { + return false; + } + var areSame = true; + for (var i = 0; i < a.Length; i++) + { + areSame &= (a[i] == b[i]); + } + return areSame; + } +#endif + + /// + /// Returns a hashed representation of the supplied for the specified . + /// + /// The user whose password is to be hashed. + /// The password to hash. + /// A hashed representation of the supplied for the specified . + public virtual string HashPassword(TUser user, string password) + { + if (password == null) + { + throw new ArgumentNullException(nameof(password)); + } + + return _compatibilityMode switch + { + CustomPasswordHasherMethod.formulaOne => Convert.ToBase64String(HashPasswordV2(password)), + CustomPasswordHasherMethod.formulaTwo => Convert.ToBase64String(HashPasswordV3(password)), + CustomPasswordHasherMethod.formulaThree => Convert.ToBase64String(HashPasswordV4(password)), + _ => throw new NotImplementedException() + }; + } + + private byte[] HashPassword(CustomPasswordHasherMethod formatMarker, string password, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested) + { + var salt = new byte[saltSize]; + _rng.GetBytes(salt); + + var pepperIndex = 0; + byte[] pepper = Array.Empty(); + if (formatMarker == CustomPasswordHasherMethod.formulaThree) + { + pepperIndex = _pepper.Keys.Max(); + pepper = _pepper[pepperIndex]; + } + + var saltAndPepper = salt.Concatenate(pepper); + var subkey = KeyDerivation.Pbkdf2(password, saltAndPepper, prf, iterCount, numBytesRequested); + + var offset = sizeof(byte); //formatMarker; + if (formatMarker != CustomPasswordHasherMethod.formulaOne) + { + offset += sizeof(uint); //prf + offset += sizeof(uint); //Iterations + } + if (formatMarker == CustomPasswordHasherMethod.formulaThree) + { + offset += sizeof(uint); //Pepper Index + } + offset += sizeof(uint); //Salt Size + offset += salt.Length; //Salt + + var outputBytes = new byte[offset + subkey.Length]; + outputBytes[0] = (byte)formatMarker; + offset = sizeof(byte); + if (formatMarker != CustomPasswordHasherMethod.formulaOne) + { + WriteNetworkByteOrder(outputBytes, offset, (uint)prf); + offset += sizeof(uint); + WriteNetworkByteOrder(outputBytes, offset, (uint)iterCount); + offset += sizeof(uint); + } + if (formatMarker == CustomPasswordHasherMethod.formulaThree) + { + WriteNetworkByteOrder(outputBytes, offset, (uint)pepperIndex); + offset += sizeof(uint); + } + WriteNetworkByteOrder(outputBytes, offset, (uint)saltSize); + offset += sizeof(uint); + + Buffer.BlockCopy(salt, 0, outputBytes, offset, salt.Length); + offset += salt.Length; + + Buffer.BlockCopy(subkey, 0, outputBytes, offset, subkey.Length); + return outputBytes; + } + + private byte[] HashPasswordV2(string password) + { + return HashPassword(CustomPasswordHasherMethod.formulaOne, + password, + prf: KeyDerivationPrf.HMACSHA1, + iterCount: 1000, + saltSize: 128 / 8, + numBytesRequested: 256 / 8); + } + + private byte[] HashPasswordV3(string password) + { + return HashPassword(CustomPasswordHasherMethod.formulaTwo, + password, + prf: KeyDerivationPrf.HMACSHA256, + iterCount: _iterCount, + saltSize: 128 / 8, + numBytesRequested: 256 / 8); + } + + private byte[] HashPasswordV4(string password) + { + return HashPassword(CustomPasswordHasherMethod.formulaThree, + password, + prf: KeyDerivationPrf.HMACSHA512, + iterCount: _iterCount, + saltSize: 128 / 8, + numBytesRequested: 512 / 8); + } + + private static uint ReadNetworkByteOrder(byte[] buffer, int offset) + { + return ((uint)(buffer[offset + 0]) << 24) + | ((uint)(buffer[offset + 1]) << 16) + | ((uint)(buffer[offset + 2]) << 8) + | ((uint)(buffer[offset + 3])); + } + + /// + /// Returns a indicating the result of a password hash comparison. + /// + /// The user whose password should be verified. + /// The hash value for a user's stored password. + /// The password supplied for comparison. + /// A indicating the result of a password hash comparison. + /// Implementations of this method should be time consistent. + public virtual PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword) + { + if (hashedPassword == null) + { + throw new ArgumentNullException(nameof(hashedPassword)); + } + if (providedPassword == null) + { + throw new ArgumentNullException(nameof(providedPassword)); + } + + var decodedHashedPassword = Convert.FromBase64String(hashedPassword); + + // read the format marker from the hashed password + if (decodedHashedPassword.Length == 0) + { + return PasswordVerificationResult.Failed; + } + + var customPasswordHasherMethod = (CustomPasswordHasherMethod)decodedHashedPassword[0]; + int embeddedIterCount; + + switch (customPasswordHasherMethod) + { + case CustomPasswordHasherMethod.formulaOne: + if (VerifyHashedPasswordV2(decodedHashedPassword, providedPassword)) + { + // This is an old password hash format - the caller needs to rehash if we're not running in an older compat mode. + return _compatibilityMode != customPasswordHasherMethod + ? PasswordVerificationResult.SuccessRehashNeeded + : PasswordVerificationResult.Success; + } + else + { + return PasswordVerificationResult.Failed; + } + + case CustomPasswordHasherMethod.formulaTwo: + if (VerifyHashedPasswordV3(decodedHashedPassword, providedPassword, out embeddedIterCount)) + { + // If this hasher was configured with a higher iteration count, change the entry now. + return embeddedIterCount < _iterCount || _compatibilityMode != customPasswordHasherMethod + ? PasswordVerificationResult.SuccessRehashNeeded + : PasswordVerificationResult.Success; + } + else + { + return PasswordVerificationResult.Failed; + } + + case CustomPasswordHasherMethod.formulaThree: + if (VerifyHashedPasswordV4(decodedHashedPassword, providedPassword, out embeddedIterCount)) + { + //todo upgrade this code to require rehash if new pepper available. + // If this hasher was configured with a higher iteration count, change the entry now. + return (embeddedIterCount < _iterCount) || _compatibilityMode != customPasswordHasherMethod + ? PasswordVerificationResult.SuccessRehashNeeded + : PasswordVerificationResult.Success; + } + + return PasswordVerificationResult.Failed; + + default: + return PasswordVerificationResult.Failed; // unknown format marker + } + } + + private static bool VerifyHashedPasswordV2(byte[] hashedPassword, string password) + { + const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes + const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes + const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits + const int SaltSize = 128 / 8; // 128 bits + + // We know ahead of time the exact length of a valid hashed password payload. + if (hashedPassword.Length != 1 + SaltSize + Pbkdf2SubkeyLength) + { + return false; // bad size + } + + var salt = new byte[SaltSize]; + Buffer.BlockCopy(hashedPassword, 1, salt, 0, salt.Length); + + var expectedSubkey = new byte[Pbkdf2SubkeyLength]; + Buffer.BlockCopy(hashedPassword, 1 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); + + // Hash the incoming password and verify it + var actualSubkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength); +#if NETSTANDARD2_0 + return ByteArraysEqual(actualSubkey, expectedSubkey); +#elif NETCOREAPP + return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey); +#else +#error Update target frameworks +#endif + } + + private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string password, out int iterCount) + { + iterCount = default; + + try + { + // Read header information + var prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1); + iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5); + var saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9); + + // Read the salt: must be >= 128 bits + if (saltLength < 128 / 8) + { + return false; + } + var salt = new byte[saltLength]; + Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length); + + // Read the subkey (the rest of the payload): must be >= 128 bits + var subkeyLength = hashedPassword.Length - 13 - salt.Length; + if (subkeyLength < 128 / 8) + { + return false; + } + var expectedSubkey = new byte[subkeyLength]; + Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); + + // Hash the incoming password and verify it + var actualSubkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, subkeyLength); +#if NETSTANDARD2_0 + return ByteArraysEqual(actualSubkey, expectedSubkey); +#elif NETCOREAPP + return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey); +#else +#error Update target frameworks +#endif + } + catch + { + // This should never occur except in the case of a malformed payload, where + // we might go off the end of the array. Regardless, a malformed payload + // implies verification failed. + return false; + } + } + + private bool VerifyHashedPasswordV4(byte[] hashedPassword, string password, out int iterationCount) + { + iterationCount = default; + + try + { + // Read header information + var prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1); + iterationCount = (int)ReadNetworkByteOrder(hashedPassword, 5); + var pepperIndex = (int)ReadNetworkByteOrder(hashedPassword, 9); + var saltLength = (int)ReadNetworkByteOrder(hashedPassword, 13); + + // Read the salt: must be >= 128 bits + if (saltLength < 128 / 8) + { + return false; + } + var salt = new byte[saltLength]; + Buffer.BlockCopy(hashedPassword, 17, salt, 0, salt.Length); + + // Read the subkey (the rest of the payload): must be >= 128 bits + var subkeyLength = hashedPassword.Length - 17 - salt.Length; + if (subkeyLength < 128 / 8) + { + return false; + } + + var expectedSubkey = new byte[subkeyLength]; + Buffer.BlockCopy(hashedPassword, 17 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); + + var pepper = _pepper[pepperIndex]; + + var saltAndPepper = salt.Concatenate(pepper); + + // Hash the incoming password and verify it + var actualSubKey = KeyDerivation.Pbkdf2(password, saltAndPepper, prf, iterationCount, subkeyLength); +#if NETSTANDARD2_0 + return ByteArraysEqual(actualSubkey, expectedSubkey); +#elif NETCOREAPP + return CryptographicOperations.FixedTimeEquals(actualSubKey, expectedSubkey); +#else +#error Update target frameworks +#endif + } + catch + { + // This should never occur except in the case of a malformed payload, where + // we might go off the end of the array. Regardless, a malformed payload + // implies verification failed. + return false; + } + } + + private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value) + { + buffer[offset + 0] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)(value >> 0); + } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasherMethod.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasherMethod.cs new file mode 100644 index 0000000..59b4f4d --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasherMethod.cs @@ -0,0 +1,8 @@ +namespace e_suite.Nuget.PasswordHasher; + +public enum CustomPasswordHasherMethod +{ + formulaOne = 0, + formulaTwo = 1, + formulaThree = 2 +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasherOptions.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasherOptions.cs new file mode 100644 index 0000000..572c154 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/CustomPasswordHasherOptions.cs @@ -0,0 +1,45 @@ +namespace e_suite.Nuget.PasswordHasher; + +/// +/// Specifies options for password hashing. +/// +public class CustomPasswordHasherOptions +{ + public CustomPasswordHasherOptions() + { + PepperDictionary = new Dictionary + { + {0, Array.Empty()} + }; + } + /// + /// Gets or sets the compatibility mode used when hashing passwords. + /// + /// + /// The compatibility mode used when hashing passwords. + /// + /// + /// The default compatibility mode is 'ASP.NET Identity version 3'. + /// + public CustomPasswordHasherMethod CompatibilityMode { get; set; } = CustomPasswordHasherMethod.formulaThree; + + /// + /// Gets or sets the number of iterations used when hashing passwords using PBKDF2. + /// + /// + /// The number of iterations used when hashing passwords using PBKDF2. + /// + /// + /// This value is only used when the compatibility mode is set to 'V3'. + /// The value must be a positive integer. The default value is 10,000. + /// + public int IterationCount { get; set; } = 10000; + + /// + /// Add pepper byte arrays to apply to the password before hashing. + /// The pepper with the highest index will be used for hashing new passwords. + /// Older peppers added to the list allow verification against older hashed passwords. + /// Index 0 is reserved to indicate that no pepper is used. + /// + public Dictionary PepperDictionary { get; } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/IPassword.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/IPassword.cs new file mode 100644 index 0000000..fbef480 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/IPassword.cs @@ -0,0 +1,6 @@ +namespace e_suite.Nuget.PasswordHasher; + +public interface IPassword +{ + string Password { get; set; } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/Resources.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/Resources.cs new file mode 100644 index 0000000..a35b709 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/Resources.cs @@ -0,0 +1,7 @@ +namespace e_suite.Nuget.PasswordHasher; + +public static class Resources +{ + public static readonly string InvalidPasswordHasherIterationCount = "Invalid password hasher iteration count"; + public static readonly string InvalidPasswordHasherCompatibilityMode = "Invalid password hasher compatibility mode"; +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/ServiceCollectionExtensions.cs b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..31372ef --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/ServiceCollectionExtensions.cs @@ -0,0 +1,22 @@ +using System.Text; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace e_suite.Nuget.PasswordHasher; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddCustomPasswordHasher(this IServiceCollection services, IConfiguration configuration) + { + var authConfigurationSection = configuration.GetSection("AuthConfig"); + var pepper = authConfigurationSection["pepper"]; + + services.Configure(options => + options.PepperDictionary.Add(1, Encoding.UTF8.GetBytes(pepper!))); + + services.AddTransient, CustomPasswordHasher>(); + + return services; + } +} \ No newline at end of file diff --git a/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.csproj b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.csproj new file mode 100644 index 0000000..9922045 --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher/e-suite.Nuget.PasswordHasher.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Nuget.PasswordHasher + enable + enable + + e_suite.Nuget.PasswordHasher + + e-suite Development Team + Custom password hasher with support for SHA512 and peppers in addition to salted passwords + true + + + + + + diff --git a/e-suite.Nuget.PasswordHasher/nuget.config b/e-suite.Nuget.PasswordHasher/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Nuget.PasswordHasher/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Scheduler/.dockerignore b/e-suite.Scheduler/.dockerignore new file mode 100644 index 0000000..bdca33b --- /dev/null +++ b/e-suite.Scheduler/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/e-suite.Scheduler/.gitattributes b/e-suite.Scheduler/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Scheduler/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Scheduler/.gitignore b/e-suite.Scheduler/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Scheduler/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Scheduler/.runsettings b/e-suite.Scheduler/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Scheduler/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Scheduler/README.md b/e-suite.Scheduler/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Scheduler/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Scheduler/azure-pipelines.yml b/e-suite.Scheduler/azure-pipelines.yml new file mode 100644 index 0000000..ba12d6c --- /dev/null +++ b/e-suite.Scheduler/azure-pipelines.yml @@ -0,0 +1,106 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(postfix)$(branchName) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: ubuntu-latest # ubuntu-latest - set to windows-latest or another Windows vmImage for Windows builds + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + containerRegistry: esuite.azurecr.io + DOCKER_BUILDKIT: 1 + + imageName: 'e-suite.Scheduler' + + publishPath: $(Build.Repository.LocalPath)/build/e-suite.Scheduler + + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + branchName: '' + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}: + branchName: $[ replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-' ) ] + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}: + branchName: $[ replace(replace(variables['System.PullRequest.TargetBranch'], 'refs/heads/', ''), '/', '-' ) ] + + ${{ if eq(variables['branchName'], '') }}: + postfix: '' + ${{ else }}: + postfix: '-' + +steps: +- task: UseDotNet@2 + displayName: 'Set .net core version' + inputs: + version: '9.0.x' + +- task: DotNetCoreCLI@2 + displayName: 'Nuget Restore' + inputs: + command: 'restore' + feedsToUse: config + projects: '**/*.csproj' + nugetConfigPath: nuget.config + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + arguments: '--configuration $(buildConfiguration)' + displayName: 'dotnet build $(buildConfiguration)' + +- task: DotNetCoreCLI@2 + displayName: 'Run Tests' + inputs: + command: test + projects: '**/*Tests/*.csproj' + arguments: '--configuration $(buildConfiguration) --collect "Code coverage" --settings .runsettings' + +- task: DotNetCoreCLI@2 + displayName: 'Publish e-suite.Scheduler' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: publish + projects: 'e-suite.Scheduler/e-suite.Scheduler.csproj' + publishWebProjects: false + arguments: -c $(BuildConfiguration) -o build + zipAfterPublish: false + +- powershell: | + Write-Host "Show all folder content" + Get-ChildItem -Path $(publishPath)\*.* -Recurse -Force | % { $_.FullName } + errorActionPreference: continue + displayName: 'PowerShell Script List folder structure' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + continueOnError: true + +- task: Docker@2 + displayName: Build e-suite.Scheduler Image + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: build + repository: $(imageName) + buildContext: $(publishPath) + Dockerfile: $(publishPath)/Dockerfile.Azure + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) + +- task: Docker@2 + displayName: Push e-suite.Scheduler + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: push + repository: $(imageName) + containerRegistry: | + $(containerRegistry) + tags: | + $(Build.BuildNumber) \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler.UnitTests/NightlyCleanUpUnitTests.cs b/e-suite.Scheduler/e-suite.Scheduler.UnitTests/NightlyCleanUpUnitTests.cs new file mode 100644 index 0000000..7487f19 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler.UnitTests/NightlyCleanUpUnitTests.cs @@ -0,0 +1,42 @@ +using e_suite.Messaging.Common; +using e_suite.Scheduler.Jobs; +using e_suite.UnitTestCore; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; + +namespace e_suite.MessageProcessor.UnitTests; + +[TestFixture] +public class NightlyCleanUpUnitTests : TestBase +{ + protected Mock DatabaseMessageSenderMock { get; set; } = null!; + protected Mock LoggerMock { get; set; } = null!; + protected NightlyCleanUp NightlyCleanUp { get; set; } = null!; + + [SetUp] + public override Task Setup() + { + DatabaseMessageSenderMock = new Mock(); + LoggerMock = new Mock(); + + NightlyCleanUp = new NightlyCleanUp(DatabaseMessageSenderMock.Object, LoggerMock.Object); + + return base.Setup(); + } + + [Test] + public async Task NightlyCleanUp_WhenCalled_InvokesExpectedMaintenanceMethods() + { + //Arrange + + //Act + await NightlyCleanUp.ExecuteAsync(); + + //Assert + DatabaseMessageSenderMock.Verify( x => x.PostClearOldEmailActions(), Times.Once); + DatabaseMessageSenderMock.Verify(x => x.PostClearOldPerformanceData(), Times.Once); + DatabaseMessageSenderMock.Verify(x => x.PostClearOldSentinelData(), Times.Once); + } + +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler.UnitTests/NightlySigmaImportUnitTests.cs b/e-suite.Scheduler/e-suite.Scheduler.UnitTests/NightlySigmaImportUnitTests.cs new file mode 100644 index 0000000..dfcf18b --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler.UnitTests/NightlySigmaImportUnitTests.cs @@ -0,0 +1,41 @@ +using e_suite.Messaging.Common; +using e_suite.Scheduler.Jobs; +using e_suite.UnitTestCore; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; + +namespace e_suite.MessageProcessor.UnitTests; + +[TestFixture] +public class NightlySigmaImportUnitTests : TestBase +{ + protected Mock SigmaImportMessageSenderMock { get; set; } = null!; + protected Mock LoggerMock { get; set; } = null!; + protected NightlySigmaImport NightlySigmaImport { get; set; } = null!; + + [SetUp] + public override Task Setup() + { + SigmaImportMessageSenderMock = new Mock(); + LoggerMock = new Mock(); + + NightlySigmaImport = new NightlySigmaImport(SigmaImportMessageSenderMock.Object, LoggerMock.Object); + + return base.Setup(); + } + + [Test] + public async Task NightlyCleanUp_WhenCalled_InvokesExpectedMaintenanceMethods() + { + //Arrange + + //Act + await NightlySigmaImport.ExecuteAsync(); + + //Assert + SigmaImportMessageSenderMock.Verify(x => x.PostImportGMGProfiles(), Times.Once); + SigmaImportMessageSenderMock.Verify(x => x.PostImportPrintSpecifications(), Times.Once); + } + +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler.UnitTests/e-suite.Scheduler.UnitTests.csproj b/e-suite.Scheduler/e-suite.Scheduler.UnitTests/e-suite.Scheduler.UnitTests.csproj new file mode 100644 index 0000000..4378482 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler.UnitTests/e-suite.Scheduler.UnitTests.csproj @@ -0,0 +1,25 @@ + + + + net10.0 + e_suite.MessageProcessor.UnitTests + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/e-suite.Scheduler/e-suite.Scheduler.sln b/e-suite.Scheduler/e-suite.Scheduler.sln new file mode 100644 index 0000000..8654c1d --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Scheduler", "e-suite.Scheduler\e-suite.Scheduler.csproj", "{649C1AFB-8ACE-4413-8DEA-447C5E17BC44}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{BF33AD39-319C-4E94-9B38-A84F0413C66C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{65C590F8-B684-480D-B0F3-7400CFD3D233}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Scheduler.UnitTests", "e-suite.Scheduler.UnitTests\e-suite.Scheduler.UnitTests.csproj", "{61716028-432E-4680-860C-F5CCF929A2F4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {649C1AFB-8ACE-4413-8DEA-447C5E17BC44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {649C1AFB-8ACE-4413-8DEA-447C5E17BC44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {649C1AFB-8ACE-4413-8DEA-447C5E17BC44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {649C1AFB-8ACE-4413-8DEA-447C5E17BC44}.Release|Any CPU.Build.0 = Release|Any CPU + {61716028-432E-4680-860C-F5CCF929A2F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61716028-432E-4680-860C-F5CCF929A2F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61716028-432E-4680-860C-F5CCF929A2F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61716028-432E-4680-860C-F5CCF929A2F4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {65C590F8-B684-480D-B0F3-7400CFD3D233} = {BF33AD39-319C-4E94-9B38-A84F0413C66C} + {61716028-432E-4680-860C-F5CCF929A2F4} = {65C590F8-B684-480D-B0F3-7400CFD3D233} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {84186740-0D52-4A90-B21D-6299068A73F8} + EndGlobalSection +EndGlobal diff --git a/e-suite.Scheduler/e-suite.Scheduler/DependencyInjection/CoreRegistrationModule.cs b/e-suite.Scheduler/e-suite.Scheduler/DependencyInjection/CoreRegistrationModule.cs new file mode 100644 index 0000000..a8c435c --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/DependencyInjection/CoreRegistrationModule.cs @@ -0,0 +1,35 @@ +using Autofac; +using e_suite.Database.Core; +using e_suite.Database.SqlServer; +using e_suite.Scheduler.Jobs; +using eSuite.Core.Clock; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.Scheduler.DependencyInjection; + +/// +/// Used as a the primary location for IOC type registration for e-suite. +/// +public class CoreRegistrationModule : Module +{ + /// + /// Use the builder to register all the types and interfaces that the API requires to operate properly. + /// + /// + protected override void Load(ContainerBuilder builder) + { + var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder.AddConsole()); + builder.Register( x=> loggerFactory.CreateLogger("e-Suite.Scheduler")).As().SingleInstance(); + IClock clock = new UtcClock(); + builder.RegisterInstance(clock).As().SingleInstance(); + + builder.RegisterInstance(ESuiteDatabaseExtension.BuildConfiguration()).As().SingleInstance(); + builder.Register(c => ESuiteDatabaseExtension.CreateDatabase(clock).GetAwaiter().GetResult()).As().InstancePerLifetimeScope(); + + Messaging.Common.DependencyInjection.CoreRegistrationModule.Load(builder); + + builder.RegisterType(); + builder.RegisterType(); + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Dockerfile b/e-suite.Scheduler/e-suite.Scheduler/Dockerfile new file mode 100644 index 0000000..6c3395e --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Dockerfile @@ -0,0 +1,21 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src +COPY ["nuget.config", "."] +COPY ["TestApp1/TestApp1.csproj", "TestApp1/"] +RUN dotnet restore "TestApp1/TestApp1.csproj" +COPY . . +WORKDIR "/src/TestApp1" +RUN dotnet build "TestApp1.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "TestApp1.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "e-suite.Scheduler.dll"] \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Dockerfile.Azure b/e-suite.Scheduler/e-suite.Scheduler/Dockerfile.Azure new file mode 100644 index 0000000..e697446 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Dockerfile.Azure @@ -0,0 +1,9 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 as base +ENV DOTNET_ENVIRONMENT=Development +WORKDIR /app +COPY . . +EXPOSE 80 +EXPOSE 443 +ENTRYPOINT ["dotnet", "e-suite.Scheduler.dll"] \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Extensions/DateTimeOffsetExtensions.cs b/e-suite.Scheduler/e-suite.Scheduler/Extensions/DateTimeOffsetExtensions.cs new file mode 100644 index 0000000..931eab1 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Extensions/DateTimeOffsetExtensions.cs @@ -0,0 +1,13 @@ +namespace e_suite.Scheduler.Extensions; + +public static class DateTimeOffsetExtensions +{ + public static DateTimeOffset SetToMidnight( this DateTimeOffset dateTimeOffset) + { + return dateTimeOffset + .AddHours(-dateTimeOffset.Hour) + .AddMinutes(-dateTimeOffset.Minute) + .AddSeconds(-dateTimeOffset.Second) + .AddMilliseconds(-dateTimeOffset.Millisecond); + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/GlobalSuppressions.cs b/e-suite.Scheduler/e-suite.Scheduler/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Scheduler/e-suite.Scheduler/ISchedule.cs b/e-suite.Scheduler/e-suite.Scheduler/ISchedule.cs new file mode 100644 index 0000000..048970a --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/ISchedule.cs @@ -0,0 +1,8 @@ +using eSuite.Core.Clock; + +namespace e_suite.Scheduler; + +public interface ISchedule +{ + DateTimeOffset NextScheduledExecution(IClock clock); +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Jobs/NightlyCleanUp.cs b/e-suite.Scheduler/e-suite.Scheduler/Jobs/NightlyCleanUp.cs new file mode 100644 index 0000000..adf2c13 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Jobs/NightlyCleanUp.cs @@ -0,0 +1,28 @@ +using e_suite.Messaging.Common; +using e_suite.Scheduler.Scheduler; +using Microsoft.Extensions.Logging; + +namespace e_suite.Scheduler.Jobs; + +[Daily(hour:3)] +public class NightlyCleanUp : IJob +{ + private readonly IDatabaseMessageSender _databaseMessageSender; + + private readonly ILogger _logger; + + public NightlyCleanUp(IDatabaseMessageSender databaseMessageSender, ILogger logger) + { + _databaseMessageSender = databaseMessageSender; + _logger = logger; + } + + public Task ExecuteAsync() + { + _databaseMessageSender.PostClearOldEmailActions(); + _databaseMessageSender.PostClearOldPerformanceData(); + _databaseMessageSender.PostClearOldSentinelData(); + _logger.LogInformation("NightlyCleanUp messages sent"); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Jobs/NightlySigmaImport.cs b/e-suite.Scheduler/e-suite.Scheduler/Jobs/NightlySigmaImport.cs new file mode 100644 index 0000000..9290082 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Jobs/NightlySigmaImport.cs @@ -0,0 +1,27 @@ +using e_suite.Messaging.Common; +using e_suite.Scheduler.Scheduler; +using Microsoft.Extensions.Logging; + +namespace e_suite.Scheduler.Jobs; + +[Daily(hour: 1, minute: 15)] +public class NightlySigmaImport : IJob +{ + private readonly ISigmaImportMessageSender _sigmaImportMessageSender; + + private readonly ILogger _logger; + + public NightlySigmaImport(ISigmaImportMessageSender sigmaImportMessageSender, ILogger logger) + { + _sigmaImportMessageSender = sigmaImportMessageSender; + _logger = logger; + } + + public Task ExecuteAsync() + { + _sigmaImportMessageSender.PostImportGMGProfiles(); + _sigmaImportMessageSender.PostImportPrintSpecifications(); + _logger.LogInformation("NightlySigmaImport messages sent"); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Program.cs b/e-suite.Scheduler/e-suite.Scheduler/Program.cs new file mode 100644 index 0000000..f543d2c --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Program.cs @@ -0,0 +1,31 @@ + +using Autofac; +using Autofac.Extensions.DependencyInjection; +using e_suite.Scheduler; +using e_suite.Scheduler.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +var hostBuilder = new HostBuilder() + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureContainer(builder => + { + builder.RegisterModule(new CoreRegistrationModule()); + } + ) + // Add configuration, logging, ... + .ConfigureServices((hostContext, services) => + { + // Add your services with dependency injection. + services + .AddLogging(loggerBuilder => + { + loggerBuilder.ClearProviders(); + loggerBuilder.AddConsole(); + }); + + services.AddHostedService(); + }); + +hostBuilder.Build().Run(); \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/ScheduledJob.cs b/e-suite.Scheduler/e-suite.Scheduler/ScheduledJob.cs new file mode 100644 index 0000000..cff5bc9 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/ScheduledJob.cs @@ -0,0 +1,63 @@ +using e_suite.Scheduler.Scheduler; +using eSuite.Core.Clock; + +namespace e_suite.Scheduler; + +public class ScheduledJob +{ + private readonly IClock _clock; + private DateTimeOffset _nextScheduledExecution = DateTimeOffset.MinValue; + private DateTimeOffset _lastExecuted = DateTimeOffset.MinValue; + private ISchedule _schedule = null!; + + public ScheduledJob(IClock clock) + { + _clock = clock; + } + + public IJob Job { get; set; } = null!; + + public ISchedule Schedule + { + get => _schedule; + set + { + if (_schedule == value) + return; + + _schedule = value; + GetNextScheduledExecution(); + } + } + + public DateTimeOffset LastExecuted + { + get => _lastExecuted; + set + { + if (_lastExecuted == value) + return; + + _lastExecuted = value; + GetNextScheduledExecution(); + } + } + + public DateTimeOffset NextScheduledExecution + { + get + { + if (_nextScheduledExecution == DateTimeOffset.MinValue) + { + GetNextScheduledExecution(); + } + + return _nextScheduledExecution; + } + } + + private void GetNextScheduledExecution() + { + _nextScheduledExecution = Schedule.NextScheduledExecution(_clock); + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Scheduler/DailyAttribute.cs b/e-suite.Scheduler/e-suite.Scheduler/Scheduler/DailyAttribute.cs new file mode 100644 index 0000000..77d7848 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Scheduler/DailyAttribute.cs @@ -0,0 +1,50 @@ +using e_suite.Scheduler.Extensions; +using eSuite.Core.Clock; + +namespace e_suite.Scheduler.Scheduler; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +public class DailyAttribute : Attribute, ISchedule +{ + /// + /// + /// + /// UTC Hour when job will be triggered + public DailyAttribute(int hour) + { + Hour = hour; + } + + /// + /// + /// + /// UTC Hour when job will be triggered + /// UTC Minute when job will be triggered + public DailyAttribute(int hour, int minute) + { + Hour = hour; + Minute = minute; + } + + public int Hour { get; } + public int Minute { get; } + + + public DateTimeOffset NextScheduledExecution(IClock clock) + { + var actualTime = clock.GetNow; + var scheduledTime = actualTime + .SetToMidnight() + .AddHours(Hour) + .AddMinutes(Minute); + + if (scheduledTime < actualTime) + { + scheduledTime = scheduledTime.AddDays(1); + } + + return scheduledTime; + } + + +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Scheduler/IJob.cs b/e-suite.Scheduler/e-suite.Scheduler/Scheduler/IJob.cs new file mode 100644 index 0000000..77d9e83 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Scheduler/IJob.cs @@ -0,0 +1,6 @@ +namespace e_suite.Scheduler.Scheduler; + +public interface IJob +{ + Task ExecuteAsync(); +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/Scheduler/IntervalAttribute.cs b/e-suite.Scheduler/e-suite.Scheduler/Scheduler/IntervalAttribute.cs new file mode 100644 index 0000000..7fe11de --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/Scheduler/IntervalAttribute.cs @@ -0,0 +1,24 @@ +using eSuite.Core.Clock; + +namespace e_suite.Scheduler.Scheduler; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +public class IntervalAttribute : Attribute, ISchedule +{ + public TimeSpan Interval { get; } + + public IntervalAttribute(int hours, int minutes) + { + Interval = new TimeSpan(hours, minutes, 0); + } + + public IntervalAttribute(int days, int hours, int minutes) + { + Interval = new TimeSpan(days, hours, minutes, 0); + } + + public DateTimeOffset NextScheduledExecution(IClock clock) + { + return clock.GetNow.Add(Interval); + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/TimedHostedService.cs b/e-suite.Scheduler/e-suite.Scheduler/TimedHostedService.cs new file mode 100644 index 0000000..28baf52 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/TimedHostedService.cs @@ -0,0 +1,110 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System.Timers; +using e_suite.Scheduler.Jobs; +using e_suite.Scheduler.Scheduler; +using eSuite.Core.Clock; + +namespace e_suite.Scheduler; + +public class TimedHostedService : IHostedService +{ + private readonly List _jobs = []; + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; + private readonly IClock _clock; + private readonly System.Timers.Timer _timer; + + public TimedHostedService(ILogger logger, IServiceProvider serviceProvider, IClock clock ) + { + _timer = new System.Timers.Timer + { + Interval = 10000, + AutoReset = true, + }; + + _timer.Elapsed += ExecuteTimer; + + _logger = logger; + _serviceProvider = serviceProvider; + _clock = clock; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Timed Background Service is starting."); + + RegisterJobs(); + + _timer.Enabled = true; + ExecuteTimer(_timer, null!); + return Task.CompletedTask; + } + + private void RegisterJobs() + { + RegisterJob(); + RegisterJob(); + } + + private void RegisterJob() where T : IJob + { + var schedule = GetSchedule(typeof(T)); + + var scheduledJob = new ScheduledJob(_clock) + { + Schedule = schedule, +#pragma warning disable CS8601 //Null reference is checked for so no need to worry about it here. + Job = _serviceProvider.GetService(typeof(T)) as IJob, +#pragma warning restore CS8601 + LastExecuted = _clock.GetNow + }; + + if (scheduledJob.Job == null) + throw new ArgumentNullException(nameof(scheduledJob.Job), "job cannot be null"); + + _jobs.Add(scheduledJob); + } + + private static ISchedule GetSchedule(Type type) + { + var attributes = type.GetCustomAttributes(false); + + foreach (var attribute in attributes) + { + if (attribute is ISchedule schedule) + return schedule; + } + + throw new InvalidOperationException($"{type.FullName} does not contain a valid Schedule attribute"); + } + + private void ExecuteTimer(object? sender, ElapsedEventArgs e) + { + var now = _clock.GetNow; + + var taskList = new List(); + foreach (var job in _jobs.Where(job => job.NextScheduledExecution <= now)) + { + job.LastExecuted = now; + taskList.Add(ExecuteJobAsync(job.Job)); + } + + Task.WhenAll(taskList).GetAwaiter().GetResult(); + } + + private async Task ExecuteJobAsync(IJob job) + { + _logger.LogInformation("Executing {FullName}", job.GetType().FullName); + await job.ExecuteAsync(); + _logger.LogInformation("Executing {FullName} - Completed", job.GetType().FullName); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Timed Background Service is stopping."); + + _jobs.Clear(); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/appsettings.Development.json b/e-suite.Scheduler/e-suite.Scheduler/appsettings.Development.json new file mode 100644 index 0000000..86c3c32 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/appsettings.Development.json @@ -0,0 +1,48 @@ +{ + "baseUrl": "http://localhost:3000", + "applicationName": "e-suite", + "https_port": 7066, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "database": { + "server": "(local)", + "databaseName": "esuite", + "encrypt": true, + "trustServerCertificate": true, + "username": "esuiteApplicationUser", + "password": "Plz change me on live, thank you" + }, + "JwtConfig": { + "secret": "Z8p9YKvYnwm62sPLJVdvp3M7bQ5l0UqRGwz95ZqL", + "expirationInMinutes": 15, + "audience": "localhost", + "issuer": "localhost" + }, + "Smtp": { + "Server": "127.0.0.1", + "Port": 25, + "FromAddress": "esuite@sun-strategy.com", + "FromDisplayName": "eSuite MailService", + "EmailTimeoutHours": 48 + }, + "AuthConfig": { + "pepper": "ThisIsNotAGoodPepper" + }, + "Sentinel": { + "MaxLoginAttempts": 5, + "LoginAttemptTimeoutMinutes": 60 + }, + "Performance": { + "DaysToKeep": 31 + }, + "twoFactorAuthentication": { + "keySize": 20 + }, + "RabbitMQ": { + "hostname": "localhost" + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/appsettings.Production.json b/e-suite.Scheduler/e-suite.Scheduler/appsettings.Production.json new file mode 100644 index 0000000..4579d26 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/appsettings.Production.json @@ -0,0 +1,61 @@ +{ + "baseUrl": "http://localhost:3000", + "applicationName": "e-suite", + "https_port": 7066, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "database": { + "server": "(local)", + "databaseName": "esuite", + "encrypt": true, + "trustServerCertificate": true, + "username": "esuiteApplicationUser", + "password": "Plz change me on live, thank you" + }, + "JwtConfig": { + "secret": "Z8p9YKvYnwm62sPLJVdvp3M7bQ5l0UqRGwz95ZqL", + "expirationInMinutes": 15, + "audience": "localhost", + "issuer": "localhost" + }, + "Smtp": { + "Server": "host.docker.internal", + "Port": 25, + "FromAddress": "esuite@sun-strategy.com", + "FromDisplayName": "eSuite MailService", + "EmailTimeoutHours": 48 + }, + "AuthConfig": { + "pepper": "ThisIsNotAGoodPepper" + }, + "Sentinel": { + "MaxLoginAttempts": 5, + "LoginAttemptTimeoutMinutes": 60 + }, + "Performance": { + "DaysToKeep": 31 + }, + "twoFactorAuthentication": { + "keySize": 20 + }, + "Kestrel": { + "EndPoints": { + "Http": { + "Url": "http://+:80" + }, + "Https": { + "Url": "https://+:443" + } + } + }, + "RabbitMQ": { + "hostname": "goose-01.rmq2.cloudamqp.com", + "vhost": "zksvzyuv", + "user": "zksvzyuv", + "password": "3G7afRHDReAnIUSrjxLiS9rWsTLXXV5x" + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/appsettings.json b/e-suite.Scheduler/e-suite.Scheduler/appsettings.json new file mode 100644 index 0000000..bd52181 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/appsettings.json @@ -0,0 +1,5 @@ +{ + "RabbitMQ": { + "hostname": "localhost" + } +} \ No newline at end of file diff --git a/e-suite.Scheduler/e-suite.Scheduler/e-suite.Scheduler.csproj b/e-suite.Scheduler/e-suite.Scheduler/e-suite.Scheduler.csproj new file mode 100644 index 0000000..e532c88 --- /dev/null +++ b/e-suite.Scheduler/e-suite.Scheduler/e-suite.Scheduler.csproj @@ -0,0 +1,35 @@ + + + + Exe + net10.0 + e_suite.Scheduler + enable + enable + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/e-suite.Scheduler/nuget.config b/e-suite.Scheduler/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Scheduler/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/.gitattributes b/e-suite.Service.CustomFieldValidation/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/.gitignore b/e-suite.Service.CustomFieldValidation/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Service.CustomFieldValidation/.runsettings b/e-suite.Service.CustomFieldValidation/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/README.md b/e-suite.Service.CustomFieldValidation/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/azure-pipelines.yml b/e-suite.Service.CustomFieldValidation/azure-pipelines.yml new file mode 100644 index 0000000..861cc37 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/azure-pipelines.yml @@ -0,0 +1,141 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - master + - develop + - feature/* + - hotfix/* + - support/* + - release/* + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.sln b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.sln new file mode 100644 index 0000000..fcac566 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.CustomFieldValidation", "e-suite.Service.CustomFieldValidation\e-suite.Service.CustomFieldValidation.csproj", "{0FCA2F0F-32C4-4D52-9606-E8500308C953}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{D9755726-381A-46D4-BC47-72590F6E77C6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{BE0C1519-3748-41AF-B9E3-6D65813BF1F6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.CustomFieldValidation.UnitTests", "e-suite.Service.CustomFieldValidationUnitTests\e-suite.Service.CustomFieldValidation.UnitTests.csproj", "{9B295E83-F7E8-4CF4-8658-7F202A6CC9CA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0FCA2F0F-32C4-4D52-9606-E8500308C953}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0FCA2F0F-32C4-4D52-9606-E8500308C953}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0FCA2F0F-32C4-4D52-9606-E8500308C953}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0FCA2F0F-32C4-4D52-9606-E8500308C953}.Release|Any CPU.Build.0 = Release|Any CPU + {9B295E83-F7E8-4CF4-8658-7F202A6CC9CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B295E83-F7E8-4CF4-8658-7F202A6CC9CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B295E83-F7E8-4CF4-8658-7F202A6CC9CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B295E83-F7E8-4CF4-8658-7F202A6CC9CA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BE0C1519-3748-41AF-B9E3-6D65813BF1F6} = {D9755726-381A-46D4-BC47-72590F6E77C6} + {9B295E83-F7E8-4CF4-8658-7F202A6CC9CA} = {BE0C1519-3748-41AF-B9E3-6D65813BF1F6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {06684CB8-B3E0-469C-AE01-6E163FEB2CE7} + EndGlobalSection +EndGlobal diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/CustomFieldVaildator.cs b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/CustomFieldVaildator.cs new file mode 100644 index 0000000..9b99092 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/CustomFieldVaildator.cs @@ -0,0 +1,324 @@ +using System.ComponentModel.DataAnnotations; +using System.Globalization; +using System.Text; +using System.Text.Json; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Service.CustomFieldValidation.Models; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.CustomFieldValidation; + +public class CustomFieldValidator : ICustomFieldValidator +{ + private readonly ICustomFieldValidatorRepository _customFieldValidatorRepository; + private readonly ISequenceManager _sequenceManager; + +#pragma warning disable IDE0290 + public CustomFieldValidator(ICustomFieldValidatorRepository customFieldValidatorRepository, ISequenceManager sequenceManager) + { + _customFieldValidatorRepository = customFieldValidatorRepository; + _sequenceManager = sequenceManager; + } +#pragma warning restore IDE0290 + + public async Task> ValidateFields(AuditUserDetails auditUserDetails, IEnumerable customFieldValues, IReadOnlyCollection customFields, CancellationToken cancellationToken) + { + var results = new List() ?? + throw new ArgumentNullException(nameof(customFields)); + + var processedFields = new List(); + + foreach (var customFieldValue in customFieldValues) + { + var field = customFields.FindByGeneralIdRef(customFieldValue.Id) ?? + throw new NullReferenceException("Custom field definition not found"); + + processedFields.Add(field); + + var comparer = new CustomFieldValueComparer(); + var values = customFieldValue.Values.Distinct(comparer).Where( x => ValueIsPopulated(x.Value, field)).ToList(); + + var isAutoGeneratedField = IsAutoGeneratedField(field); + + if (isAutoGeneratedField) + { + if (values.Count == 0) + { + values.Add( new() {Value = string.Empty, DisplayValue = string.Empty }); + } + } + + var entryCount = 0; + for (var index = 0; index < values.Count; index++) + { + var value = await AssignValue(auditUserDetails, field, values[index], cancellationToken); + + entryCount++; + results.Add(await CreateValidatedCustomFieldValue(field, index, value, cancellationToken)); + } + + CheckForEntryCountLimits(field, entryCount); + } + + var missedFields = customFields.Except(processedFields).ToList(); + foreach (var field in missedFields) + { + var defaultValue = new CustomFieldValue + { + Value = field.DefaultValue, + DisplayValue = field.DefaultValue + }; + + var value = await AssignValue(auditUserDetails, field, defaultValue, cancellationToken); + + var entryCount = 0; + + if (ValueIsPopulated(value, field)) + { + entryCount++; + results.Add(await CreateValidatedCustomFieldValue(field, 0, value, cancellationToken)); + } + + CheckForEntryCountLimits(field, entryCount); + } + + ThrowIfValidationFailed(results); + + return results; + } + + private static void ThrowIfValidationFailed(List results) + { + var validationErrors = new StringBuilder(); + foreach (var result in results) + { + if (!result.Valid) + { + foreach (var error in result.ValidationErrors) + { + validationErrors.AppendLine(result.CustomField.Name + ": " + error); + } + } + } + + if (validationErrors.Length > 0) + throw new ValidationException(validationErrors.ToString().Trim()); + } + + private static bool ValueIsPopulated(object value, CustomField field) + { + if (field.FieldType == FieldType.Text) + return true; + + if (field.FieldType == FieldType.Number) + return true; + + if (value is JsonElement { ValueKind: JsonValueKind.String } element) + { + return !string.IsNullOrWhiteSpace(element.ToString()); + } + + if (value is string valueAsString) + { + return (!string.IsNullOrWhiteSpace(valueAsString)); + } + + if (value != null) + { + return true; + } + + return false; + } + + private static bool IsAutoGeneratedField(CustomField field) + { + return field.FieldType switch + { + FieldType.Sequence => true, + _ => false + }; + } + + private static void CheckForEntryCountLimits(CustomField field, int entryCount) + { + if (field.MinEntries > entryCount) + throw new MinimumRangeException($"{field.Name} Requires at least one entry"); + + if (field.MaxEntries != null && field.MaxEntries < entryCount) + throw new MaximumRangeException($"{field.Name} Can have {field.MaxEntries} entries at most"); + } + + private async Task CreateValidatedCustomFieldValue(CustomField field, int index, object value, CancellationToken cancellationToken) + { + string cleanedValue = null!; + string? displayValue = null!; + + var valueAsString = value.ToString(); + + switch (field.FieldType) + { + case FieldType.FormTemplate: + if (!string.IsNullOrWhiteSpace(valueAsString)) + { + var templateAsGeneralIdRef = ConvertValueToGeneralIdRef(value); + var template = + await _customFieldValidatorRepository.GetTemplateByGeneralRefId(templateAsGeneralIdRef!, + cancellationToken) ?? + throw new NullReferenceException($"Unable to find template with Id {value}"); + + cleanedValue = template!.Guid.ToString(); + displayValue = template.Name; + } + break; + case FieldType.Glossary: + if (!string.IsNullOrWhiteSpace(valueAsString)) + { + var valueAsGeneralIdRef = ConvertValueToGeneralIdRef(value); + + var glossary = + await _customFieldValidatorRepository.GetGlossaryByGeneralRefId(valueAsGeneralIdRef!, + cancellationToken); + cleanedValue = glossary!.Guid.ToString(); + displayValue = glossary.Name; + } + + break; + case FieldType.Domain: + if (!string.IsNullOrWhiteSpace(valueAsString)) + { + var valueAsGeneralIdRef = ConvertValueToGeneralIdRef(value); + + var domain = + await _customFieldValidatorRepository.GetDomainByGeneralRefId(valueAsGeneralIdRef!, + cancellationToken); + cleanedValue = domain!.Guid.ToString(); + displayValue = domain.Name; + } + + break; + case FieldType.Number: + cleanedValue = valueAsString!; + displayValue = valueAsString; + break; + //case FieldType.Boolean: + //case FieldType.Date: + //case FieldType.Time: + //case FieldType.DateTime: + //case FieldType.Sequence: + case FieldType.Text: + default: + cleanedValue = valueAsString!; + displayValue = valueAsString; + break; +} + + var validatedCustomFieldValue = new ValidatedCustomFieldValue + { + CustomField = field, + CustomFieldId = field.Id, + Index = index, + Value = cleanedValue, + DisplayValue = displayValue + }; + + await ValidateField(field, validatedCustomFieldValue, cancellationToken); + + return validatedCustomFieldValue; + } + + private static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + PropertyNameCaseInsensitive = true + }; + + + private static GeneralIdRef ConvertValueToGeneralIdRef(object value) + { + + GeneralIdRef valueAsGeneralIdRef; + if (value is GeneralIdRef generalIdRef) + { + valueAsGeneralIdRef = generalIdRef; + } + else + { + valueAsGeneralIdRef = JsonSerializer.Deserialize(value.ToString()!, JsonSerializerOptions)!; + } + + return valueAsGeneralIdRef; + } + + private async Task AssignValue(AuditUserDetails auditUserDetails, CustomField field, CustomFieldValue value, CancellationToken cancellationToken) + { + return field.FieldType switch + { + FieldType.Sequence => await GetNextSequenceValue(auditUserDetails, field, value, cancellationToken), + _ => value.Value + }; + } + + private async Task GetNextSequenceValue(AuditUserDetails auditUserDetails, CustomField field, CustomFieldValue value, CancellationToken cancellationToken) + { + if (!string.IsNullOrWhiteSpace(value.Value.ToString())) + return value.Value.ToString()!; + + var sequenceId = await _customFieldValidatorRepository.FindSequenceIdForCustomField(field.Id, cancellationToken); + + var sequenceValue = await _sequenceManager.NextValue(auditUserDetails, new GeneralIdRef { Id = sequenceId }, cancellationToken); + return sequenceValue.Single(); + } + + private async Task ValidateField(CustomField field, ValidatedCustomFieldValue customFieldValue, CancellationToken cancellationToken) + { + switch (field.FieldType) + { + case FieldType.Number: + var customFieldNumbers = await _customFieldValidatorRepository.GetCustomFieldNumbersAsync(field.Id, cancellationToken); + + if (string.IsNullOrWhiteSpace(customFieldValue.Value)) + { + if (field.MinEntries != 0) + { + customFieldValue.ValidationErrors.Add($"Missing required value"); + } + break; + } + + var numberValue = decimal.Parse(customFieldValue.Value); + if (numberValue < customFieldNumbers.MinimumValue) + customFieldValue.ValidationErrors.Add($"{customFieldValue.Value} must be greater than or equal to {customFieldNumbers.MinimumValue}"); + if (numberValue > customFieldNumbers.MaximumValue) + customFieldValue.ValidationErrors.Add($"{customFieldValue.Value} must be less than or equal to {customFieldNumbers.MaximumValue}"); + + customFieldValue.DisplayValue = numberValue.ToString(CultureInfo.InvariantCulture); + customFieldValue.Value = numberValue.ToString(CultureInfo.InvariantCulture); + break; + //case FieldType.Boolean: + //case FieldType.Date: + //case FieldType.Time: + //case FieldType.DateTime: + case FieldType.Text: + //todo Create text validation code. Length, Regex match, Required, case sensitive + break; + case FieldType.Sequence: + if (!ValueIsPopulated(customFieldValue.Value, field)) + customFieldValue.ValidationErrors.Add($"{field.FieldType} Requires a value"); //Should not trigger in production. + break; + case FieldType.FormTemplate: //No need to specific validate for FormTemplates. The value is already confirmed valid at this point. + case FieldType.Glossary: //No need to specific validate for Glossary items. The value is already confirmed valid at this point. + case FieldType.Domain: //No need to specific validate for Glossary items. The value is already confirmed valid at this point. + break; + default: + customFieldValue.ValidationErrors.Add($"Fields of type {field.FieldType} are not currently supported"); //Should not trigger in production. + break; + } + } +} \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/GlobalSuppressions.cs b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/GlobalSuppressions.cs new file mode 100644 index 0000000..6c3e3bd --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "", Scope = "member", Target = "~M:e_suite.Service.CustomFieldValidation.Repository.CustomFieldValidatorRepository.#ctor(e_suite.Database.Core.IEsuiteDatabaseDbContext)")] diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/IocRegistration.cs b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/IocRegistration.cs new file mode 100644 index 0000000..b37e830 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.API.Common.repository; +using e_suite.Service.CustomFieldValidation.Repository; + +namespace e_suite.Service.CustomFieldValidation; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/Models/CustomFieldValueComparer.cs b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/Models/CustomFieldValueComparer.cs new file mode 100644 index 0000000..24fa310 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/Models/CustomFieldValueComparer.cs @@ -0,0 +1,19 @@ +using e_suite.API.Common.models; + +namespace e_suite.Service.CustomFieldValidation.Models; + +public class CustomFieldValueComparer : EqualityComparer +{ + public override bool Equals(CustomFieldValue? x, CustomFieldValue? y) + { + if (x == null && y == null) return true; + if (x == null ) return false; + if (y == null) return false; + return x.Value.Equals(y.Value); + } + + public override int GetHashCode(CustomFieldValue obj) + { + return obj.Value.GetHashCode(); + } +} \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/Repository/CustomFieldValidatorRepository.cs b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/Repository/CustomFieldValidatorRepository.cs new file mode 100644 index 0000000..e794cef --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/Repository/CustomFieldValidatorRepository.cs @@ -0,0 +1,50 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Service.CustomFieldValidation.Repository; + +public class CustomFieldValidatorRepository : RepositoryBase, ICustomFieldValidatorRepository +{ + public CustomFieldValidatorRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public async Task FindSequenceIdForCustomField(long customFieldId, CancellationToken cancellationToken) + { + var item = await DatabaseDbContext.CustomFieldSequences.SingleAsync(x => x.CustomFieldId == customFieldId, cancellationToken); + + return item.SequenceId; + } + + public async Task GetTemplateByGeneralRefId(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.FormTemplates.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task GetGlossaryByGeneralRefId(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Glossaries.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task GetDomainByGeneralRefId(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + return await DatabaseDbContext.Domains.FindByGeneralIdRefAsync(generalIdRef, cancellationToken); + } + + public async Task GetCustomFieldNumbersAsync(long fieldId, CancellationToken cancellationToken) + { + return await DatabaseDbContext.CustomFieldNumber.SingleAsync(x => x.CustomFieldId == fieldId, cancellationToken); + } + + public async Task GetCustomFieldTextsAsync(long fieldId, CancellationToken cancellationToken) + { + return await DatabaseDbContext.CustomFieldText.SingleAsync(x => x.CustomFieldId == fieldId, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.csproj b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.csproj new file mode 100644 index 0000000..26df7b9 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidation.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + e_suite.Service.CustomFieldValidation + enable + enable + + + + + + + + + + + diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidationUnitTests/CustomFieldValidatorUnitTests.cs b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidationUnitTests/CustomFieldValidatorUnitTests.cs new file mode 100644 index 0000000..0cf0c11 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidationUnitTests/CustomFieldValidatorUnitTests.cs @@ -0,0 +1,893 @@ +using System.ComponentModel.DataAnnotations; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Domain; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Glossaries; +using e_suite.Service.CustomFieldValidation; +using e_suite.UnitTestCore; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; +using Microsoft.EntityFrameworkCore; +using Moq; +using NUnit.Framework; + +namespace e_suite.Service.CustomFieldValidationUnitTests; + +[TestFixture] +public class CustomFieldValidatorUnitTests : TestBase +{ + private Mock _customFieldValidatorRepositoryMock = null!; + private Mock _sequenceManagerMock = null!; + + private CustomFieldValidator _customFieldValidator = null!; + + private AuditUserDetails _auditUserDetails = null!; + + [SetUp] + public override async Task Setup() + { + await base.Setup(); + + _auditUserDetails = new() + { + UserId = 1, + UserDisplayName = "Testy McTester", + Comment = "I'm testing stuff to see if it works" + }; + + _customFieldValidatorRepositoryMock = new(); + _sequenceManagerMock = new(); + + _customFieldValidator = new(_customFieldValidatorRepositoryMock.Object, _sequenceManagerMock.Object); + } + + [Test] + public async Task ValidateFields_CalledWithEmptyValues_ReturnsNothing() + { + //Arrange + var customFieldValues = new List(); + var customFields = new List(); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(0)); + } + + [Test] + public void ValidateFields_CustomFieldsListNull_ThrowsException() + { + //Arrange + var customFieldValues = new List(); + List customFields = null!; + + //Act & Assert + + Assert.ThrowsAsync(async () => + { + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + } + + [Test] + public void ValidateFields_FieldDefinitionNotFound_ThowsExpectedException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = + [ + new () + { + Value = "TestValue", DisplayValue = "TestValue" + } + ] + } + }; + + var customFields = new List(); + + //Act & Assert + Assert.ThrowsAsync(async () => + { + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + } + + [Test] + public async Task ValidateFields_FieldDefinitionFound_ThrowsExpectedException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = "TestValue", DisplayValue = "TestValue"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Text, + DefaultValue = string.Empty + } + }; + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("TestValue")); + Assert.That(result[0].DisplayValue, Is.EqualTo("TestValue")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldContainsDuplicates_ResultsFilterOutDuplicates() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () {Value = "TestValue", DisplayValue = "TestValue"}, new() { Value = "TestValue", DisplayValue = "TestValue" }] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Text, + DefaultValue = string.Empty + } + }; + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("TestValue")); + Assert.That(result[0].DisplayValue, Is.EqualTo("TestValue")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldContainsValueMissing_DefaultValueIsCreated() + { + //Arrange + var customFieldValues = new List(); + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Text, + DefaultValue = "DefaultValue" + } + }; + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("DefaultValue")); + Assert.That(result[0].DisplayValue, Is.EqualTo("DefaultValue")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldIsSequence_ValueObtainedFromSequence() + { + //Arrange + var expectedResult = "1"; + + var customFieldValues = new List(); + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Sequence, + DefaultValue = "" + } + }; + + var sequenceValues = new List { expectedResult }; + + _sequenceManagerMock.Setup(x => x.NextValue(It.IsAny(), It.IsAny(), It.IsAny())).Returns(() => Task.FromResult>(sequenceValues)); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo(expectedResult)); + Assert.That(result[0].DisplayValue, Is.EqualTo(expectedResult)); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldIsSequenceAndValueAlreadySet_ValueIsNotChanged() + { + //Arrange + var expectedResult = "2"; + + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = expectedResult, DisplayValue = "TestValue"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Sequence, + DefaultValue = "" + } + }; + + var sequenceValues = new List { "2" }; + + _sequenceManagerMock.Setup(x => x.NextValue(It.IsAny(), It.IsAny(), It.IsAny())).Returns(() => Task.FromResult>(sequenceValues)); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo(expectedResult)); + Assert.That(result[0].DisplayValue, Is.EqualTo(expectedResult)); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public void ValidateFields_AtLeastOneEntryRequiredAndNotSupplied_ThrowsMinEntryException() + { + //Arrange + var customFieldValues = new List(); + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + Name = "TestFieldName", + FieldType = FieldType.FormTemplate, + DefaultValue = "", + MinEntries = 1 + } + }; + + //Act + var exception = Assert.ThrowsAsync(async () => + { + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"TestFieldName Requires at least one entry")); + } + + [Test] + public void ValidateFields_AtMostOneEntryRequiredAndTwoSupplied_ThrowsMaxEntryException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = "1", DisplayValue = "TestValue1"}, new() { Value = "2", DisplayValue = "TestValue2" }] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + Name = "TestFieldName", + FieldType = FieldType.Text, + DefaultValue = "", + MaxEntries = 1 + } + }; + + //Act + var exception = Assert.ThrowsAsync(async () => + { + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + + //Assert + Assert.That(exception?.Message, Is.EqualTo($"TestFieldName Can have 1 entries at most")); + } + + [Test] + public void ValidateFields_FieldIsFormTemplateAndTemplateNotFound_ThrowsException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new() + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = "{\"id\":1}", DisplayValue = "TestValue1"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.FormTemplate, + DefaultValue = "" + } + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + } + + [Test] + public async Task ValidateFields_FieldIsFormTemplateAndTemplateFound_ReturnsExpectedResult() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = "{\"id\":1}", DisplayValue = "TestValue1"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.FormTemplate, + DefaultValue = "" + } + }; + + var formTemplate = new FormTemplate + { + Id = 1, + Name = "TestForm", + Guid = new("5D2D337A-EA31-4805-A580-F148D02E5A10") + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetTemplateByGeneralRefId(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(formTemplate)!); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("5D2D337A-EA31-4805-A580-F148D02E5A10".ToLower())); + Assert.That(result[0].DisplayValue, Is.EqualTo("TestForm")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public void ValidateFields_FieldIsGlossaryAndItemNotFound_ThrowsException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new() + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = "{\"id\":1}", DisplayValue = "TestValue1"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Glossary, + DefaultValue = "" + } + }; + + //Act & Assert + Assert.ThrowsAsync(async () => + { + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + } + + [Test] + public async Task ValidateFields_FieldIsGlossaryAndItemFound_ReturnsExpectedResult() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("{5814570A-7830-4160-9F64-5596A83616EC}") + }, + Values = [new () { Value = "{\"id\":1}", DisplayValue = "TestValue1"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("{5814570A-7830-4160-9F64-5596A83616EC}"), + FieldType = FieldType.Glossary, + DefaultValue = "" + } + }; + + var formTemplate = new Glossary + { + Id = 1, + Name = "TestGlossary", + Guid = new("2f28ac0a-d681-4ac1-82ff-aa423ca0e8fe") + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetGlossaryByGeneralRefId(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(formTemplate)!); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("2f28ac0a-d681-4ac1-82ff-aa423ca0e8fe")); + Assert.That(result[0].DisplayValue, Is.EqualTo("TestGlossary")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldIsDomainAndItemFound_ReturnsExpectedResult() + { + //Arrange + var customFieldGuid = new Guid("1a0bb5ad-201c-49d5-91f6-6b2326418525"); + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = customFieldGuid + }, + Values = [new () { Value = "{\"id\":1}", DisplayValue = "TestValue1"}] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = customFieldGuid, + FieldType = FieldType.Domain, + DefaultValue = "" + } + }; + + var formTemplate = new Domain + { + Id = 1, + Name = "Test domain", + Guid = new("c3856531-cb23-4559-9cb4-5d600c8ab457") + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetDomainByGeneralRefId(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(formTemplate)!); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("c3856531-cb23-4559-9cb4-5d600c8ab457")); + Assert.That(result[0].DisplayValue, Is.EqualTo("Test domain")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldIsDomainGeneralIdRefAndItemFound_ReturnsExpectedResult() + { + //Arrange + var customFieldGuid = new Guid("1a0bb5ad-201c-49d5-91f6-6b2326418525"); + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = customFieldGuid + }, + Values = + [ + new() + { + Value = new GeneralIdRef + { + Id = 1 + } + + } + ] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = customFieldGuid, + FieldType = FieldType.Domain, + DefaultValue = "" + } + }; + + var formTemplate = new Domain + { + Id = 1, + Name = "Test domain", + Guid = new("c3856531-cb23-4559-9cb4-5d600c8ab457") + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetDomainByGeneralRefId(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(formTemplate)!); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result[0].CustomFieldId, Is.EqualTo(1)); + Assert.That(result[0].Index, Is.EqualTo(0)); + Assert.That(result[0].Value, Is.EqualTo("c3856531-cb23-4559-9cb4-5d600c8ab457")); + Assert.That(result[0].DisplayValue, Is.EqualTo("Test domain")); + Assert.That(result[0].Valid, Is.True); + } + + [Test] + public async Task ValidateFields_FieldIsNumberAndValueIsOptionalAndNoValueSupplied_ReturnsSuccess() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new() + { + Guid = new Guid("abe34ee2-f3cc-4968-b2a9-892bdc15192f") + }, + Values = [ new CustomFieldValue { Value = ""} ] + } + }; + + var customFields = new List + { + new() + { + Id = 1, + Guid = new("abe34ee2-f3cc-4968-b2a9-892bdc15192f"), + FieldType = FieldType.Number, + DefaultValue = "", + MinEntries = 0 + } + }; + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + } + + [Test] + public async Task ValidateFields_FieldIsNumberAndValueMinusZero_ReturnsSuccessAndNumberSavedIsZero() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("abe34ee2-f3cc-4968-b2a9-892bdc15192f") + }, + Values = [new () { Value = "-0"}] + } + }; + + var customField = new CustomField + { + Id = 1, + Guid = new("abe34ee2-f3cc-4968-b2a9-892bdc15192f"), + FieldType = FieldType.Number, + DefaultValue = "", + MinEntries = 0 + }; + + var customFields = new List + { + customField + }; + + var customFieldNumber = new CustomFieldNumber + { + CustomField = customField, + CustomFieldId = customField.Id, + MaximumValue = null, + MinimumValue = null, + Step = null + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetCustomFieldNumbersAsync(1, It.IsAny())) + .Returns(Task.FromResult(customFieldNumber)!); + + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + + //Assert + Assert.That(result.Count, Is.EqualTo(1)); + + Assert.That(result[0].DisplayValue, Is.EqualTo("0")); + Assert.That(result[0].Value, Is.EqualTo("0")); + } + + [Test] + public void ValidateFields_FieldIsNumberAndValueIsBelowMinimumValue_ThrowsValidationException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("abe34ee2-f3cc-4968-b2a9-892bdc15192f") + }, + Values = [new () { Value = "2"}] + } + }; + + var customField = new CustomField + { + Id = 1, + Guid = new("abe34ee2-f3cc-4968-b2a9-892bdc15192f"), + Name = "TestNumberField1", + FieldType = FieldType.Number, + DefaultValue = "", + MinEntries = 0 + }; + + var customFields = new List + { + customField, + + }; + + var customFieldNumber = new CustomFieldNumber + { + CustomField = customField, + CustomFieldId = customField.Id, + MaximumValue = null, + MinimumValue =10, + Step = null + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetCustomFieldNumbersAsync(1, It.IsAny())) + .Returns(Task.FromResult(customFieldNumber)!); + + //Assert + var exception = Assert.ThrowsAsync(async () => + { + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + + Assert.That( exception?.Message, Is.EqualTo($"{customField.Name}: 2 must be greater than or equal to 10")); + } + + [Test] + public void ValidateFields_FieldIsNumberAndValueIsAboveMaximumValue_ThrowsValidationException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("abe34ee2-f3cc-4968-b2a9-892bdc15192f") + }, + Values = [new () { Value = "300"}] + } + }; + + var customField = new CustomField + { + Id = 1, + Guid = new("abe34ee2-f3cc-4968-b2a9-892bdc15192f"), + Name = "TestNumberField1", + FieldType = FieldType.Number, + DefaultValue = "", + MinEntries = 0 + }; + + var customFields = new List + { + customField, + + }; + + var customFieldNumber = new CustomFieldNumber + { + CustomField = customField, + CustomFieldId = customField.Id, + MaximumValue = 200, + MinimumValue = null, + Step = null + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetCustomFieldNumbersAsync(1, It.IsAny())) + .Returns(Task.FromResult(customFieldNumber)!); + + //Assert + var exception = Assert.ThrowsAsync(async () => + { + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + + Assert.That(exception?.Message, Is.EqualTo($"{customField.Name}: 300 must be less than or equal to 200")); + } + + [Test] + public void ValidateFields_FieldIsNumberAndValueRequiredButNotSupplied_ThrowsValidationException() + { + //Arrange + var customFieldValues = new List + { + new() + { + Id = new GeneralIdRef + { + Guid = new Guid("abe34ee2-f3cc-4968-b2a9-892bdc15192f") + }, + Values = [new () { Value = ""}] + } + }; + + var customField = new CustomField + { + Id = 1, + Guid = new("abe34ee2-f3cc-4968-b2a9-892bdc15192f"), + Name = "TestNumberField1", + FieldType = FieldType.Number, + DefaultValue = "", + MinEntries = 1 + }; + + var customFields = new List + { + customField, + + }; + + var customFieldNumber = new CustomFieldNumber + { + CustomField = customField, + CustomFieldId = customField.Id, + MaximumValue = 200, + MinimumValue = null, + Step = null + }; + + _customFieldValidatorRepositoryMock.Setup(x => x.GetCustomFieldNumbersAsync(1, It.IsAny())) + .Returns(Task.FromResult(customFieldNumber)!); + + //Assert + var exception = Assert.ThrowsAsync(async () => + { + //Act + var result = (await _customFieldValidator.ValidateFields(_auditUserDetails, customFieldValues, customFields, default)).ToList(); + }); + + Assert.That(exception?.Message, Is.EqualTo($"{customField.Name}: Missing required value")); + } +} diff --git a/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidationUnitTests/e-suite.Service.CustomFieldValidation.UnitTests.csproj b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidationUnitTests/e-suite.Service.CustomFieldValidation.UnitTests.csproj new file mode 100644 index 0000000..24b2640 --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/e-suite.Service.CustomFieldValidationUnitTests/e-suite.Service.CustomFieldValidation.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + e_suite.Service.CustomFieldValidationUnitTests + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Service.CustomFieldValidation/nuget.config b/e-suite.Service.CustomFieldValidation/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Service.CustomFieldValidation/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/.gitattributes b/e-suite.Service.EFlowSync/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Service.EFlowSync/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/.gitignore b/e-suite.Service.EFlowSync/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Service.EFlowSync/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Service.EFlowSync/.runsettings b/e-suite.Service.EFlowSync/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Service.EFlowSync/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/README.md b/e-suite.Service.EFlowSync/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Service.EFlowSync/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/azure-pipelines.yml b/e-suite.Service.EFlowSync/azure-pipelines.yml new file mode 100644 index 0000000..0c3a8a7 --- /dev/null +++ b/e-suite.Service.EFlowSync/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '10' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/EFlowSync/SyncEFlowPrinterCategoriesUnitTests.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/EFlowSync/SyncEFlowPrinterCategoriesUnitTests.cs new file mode 100644 index 0000000..8d922da --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/EFlowSync/SyncEFlowPrinterCategoriesUnitTests.cs @@ -0,0 +1,743 @@ +using e_suite.Database.Core.Tables.CustomFields; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Service.EFlowSync.EflowAPI; +using e_suite.Service.EFlowSync.UnitTests.Helpers; +using eSuite.Core.CustomFields; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; + +namespace e_suite.Service.EFlowSync.UnitTests.EFlowSync +{ + public class SyncEFlowPrinterCategoriesUnitTests : SyncEFlowTestBase + { + + + [SetUp] + public async Task SetUp() + { + await base.Setup(); + } + + [Test] + public void SyncEFlowPrinterCategories_NoDomainsToSync_DoesNothing() + { + //Arrange + Domains.Clear(); + Assert.That(DomainsToLookup.Data.Count(), Is.Zero); + + //Act & Assert + Assert.DoesNotThrowAsync(async() => await EFlowSync.SyncEFlowPrinterCategories(null!)); + } + + [Test] + public void SyncEFlowPrinterCategories_NullPassedAsParameter_ThrowsNullReferenceException() + { + //Arrange + + //Act & Assert + Assert.ThrowsAsync( async () => await EFlowSync.SyncEFlowPrinterCategories(null!)); + } + + [Test] + public async Task SyncEFlowPrinterCategories_EmptyListPassedAsParameter_ThrowsNullReferenceException() + { + //Arrange + foreach (var domain in Domains) + { + domain.SunriseAppId = string.Empty; //makes sure that all domains are not setup for syncing with e-flow. + } + + var domainsToSync = new List(); + + //Act & Assert + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + } + + [Test] + public void SyncEFlowPrinterCategories_FailsToGetCategoryFromEflow_ThrowsExpectedException() + { + //Arrange + var domainsToSync = new List(); + + //Act + var exception = Assert.ThrowsAsync( async() => await EFlowSync.SyncEFlowPrinterCategories(domainsToSync)); + + //Assert + Assert.That(exception!.Message, Is.EqualTo("Unable to find e-flow printer category")); + } + + [Test] + public void SyncEFlowPrinterCategories_RequestToUpdateNonExistingDomain_DoesNothingGracefully() + { + //Arrange + var domainsToSync = new List + { + new() { Guid = new Guid("{497AAEE7-496A-468C-A6A3-4C003E815CE6}") } + }; + + //Act & Assert + Assert.DoesNotThrowAsync(async () => await EFlowSync.SyncEFlowPrinterCategories(domainsToSync)); + } + + [Test] + public async Task SyncEFlowPrinterCategories_WhenCategoryDoesNotContainAnything_AddsExtraCategoryToEFlow() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers" + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + } + ); + + FakeSpecificationManagerRepository.Specifications.Add( new Specification + { + FormInstanceId = 1000, + Name = "TestSpecification", + Site = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + } + }); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Exactly(3)); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Never); + + Assert.That(testCategory.Children.Count, Is.EqualTo(1)); + var organisationCategory = testCategory.Children[0]; + Assert.That(organisationCategory.DisplayName, Is.EqualTo("MyOrganisation")); + Assert.That(organisationCategory.Children.Count, Is.EqualTo(1)); + var siteCategory = organisationCategory.Children[0]; + Assert.That(siteCategory.DisplayName, Is.EqualTo("MySite")); + Assert.That(siteCategory.Children.Count, Is.EqualTo(1)); + var specificationCategory = siteCategory.Children[0]; + Assert.That(specificationCategory.DisplayName, Is.EqualTo("TestSpecification")); + Assert.That(specificationCategory.Children.Count, Is.Zero); + } + + + [Test] + public async Task SyncEFlowPrinterCategories_WhenOrganisationSiteAndSpecAlreadyExists_ChangesNothing() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers", + Children = + [ + new CategoryInfo + { + Id = "Org1", + DisplayName = "MyOrganisation", + Children = [ + new CategoryInfo + { + Id = "Site1", + DisplayName = "MySite", + Children = [ + new CategoryInfo + { + Id = "Spec1", + DisplayName = "TestSpecification" + } + ] + } + ] + } + ] + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + + var commonSite = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + }; + + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10000, + FormInstanceId = 1000, + Name = "TestSpecification", + Site = commonSite + }); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Never); + } + + [Test] + public async Task SyncEFlowPrinterCategories_WhenNewSpecificationAddedToSite_AddsOnlyNewSpec() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers", + Children = + [ + new CategoryInfo + { + Id = "Org1", + DisplayName = "MyOrganisation", + Children = [ + new CategoryInfo + { + Id = "Site1", + DisplayName = "MySite", + Children = [ + new CategoryInfo + { + Id = "Spec1", + DisplayName = "TestSpecification" + } + ] + } + ] + } + ] + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1001, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + + var commonSite = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + }; + + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10000, + FormInstanceId = 1000, + Name = "TestSpecification", + Site = commonSite + }); + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10001, + FormInstanceId = 1000, + Name = "TestSpecification1", + Site = commonSite + }); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Once); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Never); + } + + [Test] + public async Task SyncEFlowPrinterCategories_WhenSpecificationRemoved_DeletesCorrectSpecification() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers", + Children = + [ + new CategoryInfo + { + Id = "Org1", + DisplayName = "MyOrganisation", + Children = [ + new CategoryInfo + { + Id = "Site1", + DisplayName = "MySite", + Children = [ + new CategoryInfo + { + Id = "Spec1", + DisplayName = "TestSpecification" + } + ] + } + ] + }, + new CategoryInfo + { + Id = "Org2", + DisplayName = "MyOrganisation2", + Children = [ + new CategoryInfo + { + Id = "Site2", + DisplayName = "MySite2", + Children = [ + new CategoryInfo + { + Id = "Spec2", + DisplayName = "TestSpecification2" + } + ] + } + ] + } + ] + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + + var commonSite = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + }; + + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10000, + FormInstanceId = 1000, + Name = "TestSpecification", + Site = commonSite + }); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Exactly(3)); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Never); + } + + [Test] + public async Task SyncEFlowPrinterCategories_WhenSpecificationNameChanges_UpdatedExistingSpecification() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers", + Children = + [ + new CategoryInfo + { + Id = "Org1", + DisplayName = "MyOrganisation", + Children = [ + new CategoryInfo + { + Id = "Site1", + DisplayName = "MySite", + Children = [ + new CategoryInfo + { + Id = "Spec1", + DisplayName = "TestSpecification Renamed" + } + ] + } + ] + } + ] + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + + var commonSite = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + }; + + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10000, + FormInstanceId = 1000, + Name = "TestSpecification", + Site = commonSite + }); + + FakeEFlowSyncRepository.ExternalIds.Add(("e_suite.Database.Core.Tables.Printer.Organisation", "{\"Id\":2}"), "Org1"); + FakeEFlowSyncRepository.ExternalIds.Add(("e_suite.Database.Core.Tables.Printer.Site", "{\"Id\":2}"), "Site1"); + FakeEFlowSyncRepository.ExternalIds.Add(("e_suite.Database.Core.Tables.Printer.Specification", "{\"Id\":10000}"), "Spec1"); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Once); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Never); + } + + [Test] + public async Task SyncEFlowPrinterCategories_WhenSpecificationIsRestored_RestoresCategory() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers", + Children = + [ + new CategoryInfo + { + Id = "Org1", + DisplayName = "MyOrganisation", + Children = [ + new CategoryInfo + { + Id = "Site1", + DisplayName = "MySite", + Children = [ + new CategoryInfo + { + Id = "Spec1", + DisplayName = "TestSpecification", + Deleted = new DateTimeOffset(2025, 01, 01, 00,00,00, TimeSpan.Zero) + } + ] + } + ] + } + ] + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + + var commonSite = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + }; + + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10000, + FormInstanceId = 1000, + Name = "TestSpecification", + Site = commonSite + }); + + FakeEFlowSyncRepository.ExternalIds.Add(("e_suite.Database.Core.Tables.Printer.Organisation", "{\"Id\":2}"), "Org1"); + FakeEFlowSyncRepository.ExternalIds.Add(("e_suite.Database.Core.Tables.Printer.Site", "{\"Id\":2}"), "Site1"); + FakeEFlowSyncRepository.ExternalIds.Add(("e_suite.Database.Core.Tables.Printer.Specification", "{\"Id\":10000}"), "Spec1"); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Once); + } + + [Test] + public async Task SyncEFlowPrinterCategories_WhenAttemptingToDeleteAlreadyDeletedSpeciciation_DoesNothing() + { + //Arrange + var domainsToSync = new List(); + + var testCategory = new CategoryInfo + { + Id = "Category1", + DisplayName = "e-print printers", + Children = + [ + new CategoryInfo + { + Id = "Org1", + DisplayName = "MyOrganisation", + Children = [ + new CategoryInfo + { + Id = "Site1", + DisplayName = "MySite", + Children = [ + new CategoryInfo + { + Id = "Spec1", + DisplayName = "TestSpecification" + } + ] + } + ] + }, + new CategoryInfo + { + Id = "Org2", + DisplayName = "MyOrganisation2", + Deleted = new DateTimeOffset(2025, 01, 01, 00,00,00, TimeSpan.Zero), + Children = [ + new CategoryInfo + { + Id = "Site2", + DisplayName = "MySite2", + Deleted = new DateTimeOffset(2025, 01, 01, 00,00,00, TimeSpan.Zero), + Children = [ + new CategoryInfo + { + Id = "Spec2", + DisplayName = "TestSpecification2", + Deleted = new DateTimeOffset(2025, 01, 01, 00,00,00, TimeSpan.Zero) + } + ] + } + ] + } + ] + }; + + EFlowCategoriesMock.Setup(x => x.GetCategories("Category1")).ReturnsAsync(testCategory); + + FakeFormRepository.FormInstances.Add(new FormInstance + { + Id = 1000, + FormFields = new List + { + new() + { + Id = 100, + CustomField = new CustomField + { + Guid = new Guid("{45821c2d-9d6e-4c82-ac57-965755960422}"), + FieldType = FieldType.Domain, + MaxEntries = 0 + }, + Index = 1, + Value = "63cac905-acea-48d4-9faa-25deb34de123" + } + } + }); + + var commonSite = new Site + { + Id = 2, + Name = "MySite", + Organisation = new Organisation + { + Id = 3, + Name = "MyOrganisation" + } + }; + + FakeSpecificationManagerRepository.Specifications.Add(new Specification + { + Id = 10000, + FormInstanceId = 1000, + Name = "TestSpecification", + Site = commonSite + }); + + //Act + await EFlowSync.SyncEFlowPrinterCategories(domainsToSync); + + //Assert + EFlowCategoriesMock.Verify(x => x.PostCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.DeleteCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.UpdateCategory(It.IsAny()), Times.Never); + EFlowCategoriesMock.Verify(x => x.RestoreCategory(It.IsAny()), Times.Never); + } + } +} diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeEFlowSyncRepository.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeEFlowSyncRepository.cs new file mode 100644 index 0000000..403bdce --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeEFlowSyncRepository.cs @@ -0,0 +1,23 @@ +using e_suite.Service.EFlowSync.Repository; +using e_suite.UnitTestCore; + +namespace e_suite.Service.EFlowSync.UnitTests.FakeRepositories; + +public class FakeEFlowSyncRepository : FakeRepository, IEFlowSyncRepository +{ + public Dictionary<(string, string), string> ExternalIds = new(); + + public Task GetEFlowExternalId(string entityName, string primaryKeyJson) + { + if (ExternalIds.ContainsKey((entityName, primaryKeyJson))) + return Task.FromResult(ExternalIds[(entityName, primaryKeyJson)])!; + + return Task.FromResult(null); + } + + public Task AddEflowExternalId(string entityName, string primaryKeyJson, string childId, CancellationToken cancellationToken) + { + ExternalIds[(entityName, primaryKeyJson)] = childId; + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeFormsRepository.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeFormsRepository.cs new file mode 100644 index 0000000..b9c41e2 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeFormsRepository.cs @@ -0,0 +1,169 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Helpers; +using e_suite.Database.Core.Tables.Forms; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; +using MockQueryable; + +namespace e_suite.Service.EFlowSync.UnitTests.FakeRepositories; + +public class FakeFormsRepository : FakeRepository, IFormRepository +{ + public List FormTemplates { get; set; } = []; + public List FormTemplateVersions { get; set; } = []; + public List FormInstances { get; set; } = []; + + public List FormFieldValues { get; set; } = []; + + public Task CreateNewFormVersionAsync(AuditUserDetails auditUserDetails, FormTemplateVersion formTemplateVersion, CancellationToken cancellationToken) + { + FormTemplateVersions.Add(formTemplateVersion); + return Task.CompletedTask; + } + + public IQueryable GetAllFormVersions(long templateId) + { + return FormTemplateVersions.Where(x => x.TemplateId == templateId).ToList().BuildMock(); + } + + public Task CreateTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate template, CancellationToken cancellationToken) + { + FormTemplates.Add(template); + return Task.CompletedTask; + } + + public Task DeleteAllVersionsAsync(AuditUserDetails auditUserDetails, IEnumerable formTemplateVersions, CancellationToken cancellationToken) + { + FormTemplateVersions.ForEach(x => + { + if (formTemplateVersions.Any(f => f.Id == x.Id) || formTemplateVersions.Any(f => f.Guid == x.Guid)) + { + x.Deleted = true; + } + ; + }); + return Task.CompletedTask; + } + + public Task EditFormTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate formTemplate, CancellationToken cancellationToken) + { + var form = FormTemplates.First(x => x.Id == formTemplate.Id || x.Guid == formTemplate.Guid); + form.Name = formTemplate.Name; + return Task.CompletedTask; + } + +#pragma warning disable IDE0060 // Remove unused parameter + public Task> GetAllFormVersionsAsync(long templateId, CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + return Task.FromResult(FormTemplateVersions.Where(x => x.TemplateId == templateId)); + } + + public Task GetFormTemplateVersionAsync(IGeneralIdRef templateId, CancellationToken cancellationToken) + { + return Task.FromResult(FormTemplateVersions.FirstOrDefault(x => x.Id == templateId.Id || x.Guid == templateId.Guid)); + } + + public Task GetFormTemplateWithSpecificVersionAsync(IGeneralIdRef id, long formTemplateVersionId, CancellationToken cancellationToken) + { + return Task.FromResult(FormTemplates.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid)); + } + + public Task AddFormInstance( + AuditUserDetails auditUserDetails, + FormInstance newFormInstance, + CancellationToken cancellationToken + ) + { + FormInstances.Add(newFormInstance); + return Task.CompletedTask; + } + + public Task AddFormInstances(AuditUserDetails auditUserDetails, IEnumerable newFormInstance, + CancellationToken cancellationToken) + { + FormInstances.AddRange(newFormInstance); + return Task.CompletedTask; + } + + public Task AddFormInstanceValues( + AuditUserDetails auditUserDetails, + List customFieldValues, + CancellationToken cancellationToken + ) + { + FormFieldValues.AddRange(customFieldValues); + return Task.CompletedTask; + } + + public Task GetFormInstance(GeneralIdRef createFormInstanceId, bool tracking, CancellationToken cancellationToken) + { + return Task.FromResult(FormInstances.FindByGeneralIdRef(createFormInstanceId)); + } + + public Task> GetFormInstances(IEnumerable generalIdRefs, bool tracking, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta delta, CancellationToken cancellationToken) + { + SaveCustomFieldValuesCalled = true; + return Task.CompletedTask; + } + + public Task> GetFormsContainingFieldValue(IGeneralIdRef customFieldGeneralIdRef, string value, CancellationToken cancellationToken) + { + var formInstances = new List(); + + foreach (var formInstance in FormInstances) + { + foreach (var field in formInstance.FormFields) + { + if (field.CustomField.Guid == customFieldGeneralIdRef.Guid || field.CustomField.Id == customFieldGeneralIdRef.Id) + { + formInstances.Add(formInstance); + break; + } + } + } + + return Task.FromResult>(formInstances); + } + + public bool SaveCustomFieldValuesCalled { get; set; } = false; + + public Task GetTemplateAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + var form = FormTemplates.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid); + if (form is null) + return Task.FromResult(form)!; + form!.Versions = [.. FormTemplateVersions.Where(f => f.TemplateId == form.Id).OrderBy(f => f.Version)]; + return Task.FromResult(form)!; + } + + public IQueryable GetTemplates() + { + return FormTemplates.BuildMock(); + } + +#pragma warning disable IDE0060 // Remove unused parameter + public Task> GetTemplatesAsync(CancellationToken cancellationToken) +#pragma warning restore IDE0060 // Remove unused parameter + { + return Task.FromResult((IEnumerable)FormTemplates); + } + + public Task GetTemplateWithOutLoadedRefereranceAsync(IGeneralIdRef id, CancellationToken cancellationToken) + { + var res = FormTemplates.FirstOrDefault(x => x.Id == id.Id || x.Guid == id.Guid); + if (res is null) + { + return Task.FromResult(res); + } + res.Versions = null!; + return Task.FromResult(res)!; + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeSpecificationManagerRepository.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeSpecificationManagerRepository.cs new file mode 100644 index 0000000..349f123 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/FakeRepositories/FakeSpecificationManagerRepository.cs @@ -0,0 +1,47 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Audit; +using e_suite.Database.Core.Tables.Printer; +using e_suite.UnitTestCore; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.EFlowSync.UnitTests.FakeRepositories; + +public class FakeSpecificationManagerRepository : FakeRepository, ISpecificationManagerRepository +{ + public List Specifications { get; set; } = new(); + + public IQueryable GetSpecifications() + { + throw new NotImplementedException(); + } + + public IQueryable GetSpecificationsFromForms(IEnumerable formIds) + { + return Specifications.Where(x => formIds.Contains(x.FormInstanceId)).AsQueryable(); + } + + public Task GetSpecification(GeneralIdRef generalIdRef, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateSpecification(AuditUserDetails auditUserDetails, Specification newSpecification, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CreateSpecification(AuditUserDetails auditUserDetails, IEnumerable newSpecification, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditSpecification(AuditUserDetails auditUserDetails, Specification specification, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task EditSpecification(AuditUserDetails auditUserDetails, IEnumerable specifications, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/Helpers/SyncEFlowTestBase.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/Helpers/SyncEFlowTestBase.cs new file mode 100644 index 0000000..cbbb2ee --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/Helpers/SyncEFlowTestBase.cs @@ -0,0 +1,66 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.Service.EFlowSync.EflowAPI; +using e_suite.Service.EFlowSync.UnitTests.FakeRepositories; +using e_suite.UnitTestCore; +using e_suite.Utilities.Pagination; +using Moq; + +namespace e_suite.Service.EFlowSync.UnitTests.Helpers; + +public class SyncEFlowTestBase : TestBase +{ + protected Mock DomainManagerMock { get; set; } = null!; + protected Mock EFlowCategoriesMock { get; set; } = null!; + protected FakeFormsRepository FakeFormRepository { get; set; }= null!; + protected FakeSpecificationManagerRepository FakeSpecificationManagerRepository { get; set; }= null!; + protected FakeEFlowSyncRepository FakeEFlowSyncRepository { get; set; } = null!; + protected IEFlowSync EFlowSync { get; set; } = null!; + + + public List Domains = new List(); + + public PaginatedData DomainsToLookup { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + + Domains.Add(new GetDomain + { + Guid = new Guid("{63CAC905-ACEA-48D4-9FAA-25DEB34DE123}"), + Id = 1, + Name = "TestDomain", + SunriseAppId = "Testing", + SunriseCategoryId = "Category1" + }); + Domains.Add(new GetDomain + { + Guid = new Guid("{AA176AD4-85B5-418D-80FA-B73BC7B419F0}"), + Id = 2, + Name = "MyDomain" + }); + Domains.Add(new GetDomain + { + Guid = new Guid("{D3271945-FD84-4FCA-84AC-77CC07D4BF89}"), + Id = 3, + Name = "ADifferentDomain" + }); + + DomainsToLookup = new PaginatedData + { + Data = Domains + }; + + DomainManagerMock = new Mock(); + DomainManagerMock.Setup(x => x.GetDomainsAsync(It.IsAny(), It.IsAny())).Returns( + () => Task.FromResult((IPaginatedData)DomainsToLookup)); + + EFlowCategoriesMock = new Mock(); + FakeFormRepository = new FakeFormsRepository(); + FakeSpecificationManagerRepository = new FakeSpecificationManagerRepository(); + FakeEFlowSyncRepository = new FakeEFlowSyncRepository(); + + EFlowSync = new Service.EFlowSync.EFlowSync(DomainManagerMock.Object, EFlowCategoriesMock.Object, FakeFormRepository, FakeSpecificationManagerRepository, FakeEFlowSyncRepository); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/e-suite.Service.EFlowSync.UnitTests.csproj b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/e-suite.Service.EFlowSync.UnitTests.csproj new file mode 100644 index 0000000..7449ba2 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.UnitTests/e-suite.Service.EFlowSync.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + e_suite.Service.EFlowSync.UnitTests + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.sln b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.sln new file mode 100644 index 0000000..805bdb4 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Service.EFlowSync", "e-suite.Service.EFlowSync\e-suite.Service.EFlowSync.csproj", "{593C2162-6B4D-41AD-83C7-E2AC506CC51D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{3A7AE83E-01C2-4977-AEFD-C6BE75803D57}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Service.EFlowSync.UnitTests", "e-suite.Service.EFlowSync.UnitTests\e-suite.Service.EFlowSync.UnitTests.csproj", "{5496D36A-7E2E-4A9B-B3E5-E3C0EDE1F657}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {593C2162-6B4D-41AD-83C7-E2AC506CC51D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {593C2162-6B4D-41AD-83C7-E2AC506CC51D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {593C2162-6B4D-41AD-83C7-E2AC506CC51D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {593C2162-6B4D-41AD-83C7-E2AC506CC51D}.Release|Any CPU.Build.0 = Release|Any CPU + {5496D36A-7E2E-4A9B-B3E5-E3C0EDE1F657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5496D36A-7E2E-4A9B-B3E5-E3C0EDE1F657}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5496D36A-7E2E-4A9B-B3E5-E3C0EDE1F657}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5496D36A-7E2E-4A9B-B3E5-E3C0EDE1F657}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3A7AE83E-01C2-4977-AEFD-C6BE75803D57} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {5496D36A-7E2E-4A9B-B3E5-E3C0EDE1F657} = {3A7AE83E-01C2-4977-AEFD-C6BE75803D57} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8F811A01-0909-4E6A-B30C-44013A7857F8} + EndGlobalSection +EndGlobal diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EFlowSync.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EFlowSync.cs new file mode 100644 index 0000000..13b0e4e --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EFlowSync.cs @@ -0,0 +1,187 @@ +using e_suite.API.Common; +using e_suite.API.Common.models; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Models; +using e_suite.Service.EFlowSync.EflowAPI; +using e_suite.Service.EFlowSync.Extensions; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using e_suite.Service.EFlowSync.Repository; + +namespace e_suite.Service.EFlowSync; + +public class EFlowSync : IEFlowSync +{ + private readonly IDomainManager _domainManager; + private readonly IEFlowCategories _eFlowCategories; + private readonly IFormRepository _formRepository; + private readonly ISpecificationManagerRepository _specificationManagerRepository; + private readonly IEFlowSyncRepository _eFlowSyncRepository; + + public EFlowSync(IDomainManager domainManager, IEFlowCategories eFlowCategories, IFormRepository formRepository, ISpecificationManagerRepository specificationManagerRepository, IEFlowSyncRepository eFlowSyncRepository) + { + _domainManager = domainManager; + _eFlowCategories = eFlowCategories; + _formRepository = formRepository; + _specificationManagerRepository = specificationManagerRepository; + _eFlowSyncRepository = eFlowSyncRepository; + } + + private readonly Dictionary _externalIdCache = new(); + + public async Task SyncEFlowPrinterCategories(List fullMessageDomains) + { + //Load the list of domains that need to by sync'd + var domains = (await _domainManager.GetDomainsAsync(new Paging { Page = 0 }, CancellationToken.None)).Data; + + foreach (var domain in domains) + { + if (fullMessageDomains.Count > 0) + { + if (!fullMessageDomains.Contains(domain.ToGeneralIdRef()!)) + //This domain can be skipped as a sync wasn't requested. + continue; + } + + if (string.IsNullOrWhiteSpace(domain.SunriseAppId) || string.IsNullOrWhiteSpace(domain.SunriseCategoryId)) + //Domain is not setup for sync with e-flow, so no point doing any more work. + continue; + + //Get the category + _eFlowCategories.ApiKey = domain.SunriseAppId; + var eFlowPrinterCategory = await _eFlowCategories.GetCategories(domain.SunriseCategoryId); + if (eFlowPrinterCategory == null) + throw new NullReferenceException("Unable to find e-flow printer category"); + + _externalIdCache.Clear(); + + await AddMissingCategories(domain, eFlowPrinterCategory, CancellationToken.None); + + await PruneUnneededCategories(eFlowPrinterCategory); + } + } + + private async Task PruneUnneededCategories(CategoryInfo parentCategory) + { + var deleteList = new List(); + + //Now to prune the eFlowPrinterCategory structure + foreach (var category in parentCategory.Children) + { + if (category.Deleted != null) + continue; + + await PruneUnneededCategories(category); + + if (_externalIdCache.ContainsValue(category.Id)) + continue; + + if (category.Children.Count == 0) + { + deleteList.Add(category); + await _eFlowCategories.DeleteCategory(category); + } + } + + foreach (var category in deleteList) + parentCategory.Children.Remove(category); + } + + private readonly Guid _domainGuid = new("45821c2d-9d6e-4c82-ac57-965755960422"); + + private async Task AddMissingCategories(GetDomain domain, CategoryInfo eFlowPrinterCategory, CancellationToken cancellationToken) + { + //Get all the forms that have a formfield containing the domainGuid + var domainCustomFieldGeneralIdRef = new GeneralIdRef { Guid = _domainGuid }; + + var allFormsForDomain = await _formRepository.GetFormsContainingFieldValue(domainCustomFieldGeneralIdRef, domain.Guid.ToString(), cancellationToken); + var formIds = allFormsForDomain.Select(x => x.Id); + + //Get all specifications that use the forms + var specificationsForDomain = _specificationManagerRepository.GetSpecificationsFromForms(formIds).ToList(); + + foreach (var specification in specificationsForDomain) + { + var organisation = specification.Site.Organisation; + var currentOrganisationCategory = await EnsureCategoryExists(eFlowPrinterCategory, organisation, cancellationToken); + + var site = specification.Site; + var currentSiteCategory = await EnsureCategoryExists(currentOrganisationCategory, site, cancellationToken); + + var currentPrintSpecCategory = await EnsureCategoryExists(currentSiteCategory, specification, cancellationToken); + } + } + + private async Task EnsureCategoryExists(CategoryInfo parent, IName obj, CancellationToken cancellationToken) + { + var category = await FindOrAddCategory(parent, obj, cancellationToken); + + if (category.Deleted != null) + { + + category.Deleted = null; + await _eFlowCategories.RestoreCategory(category); + } + + if (category.DisplayName != obj.Name) + { + category.DisplayName = obj.Name; + await _eFlowCategories.UpdateCategory(category); + } + + return category; + } + + private async Task FindOrAddCategory(CategoryInfo parent, IName obj, CancellationToken cancellationToken) + { + var type = obj.GetType(); + var entityName = type.FullName ?? type.Name; + var primaryKeyJson = type.PrimaryKeyDictionary(obj).ToPrimaryKeyJson(); + + if (!_externalIdCache.TryGetValue(obj, out var externalId)) + { + externalId = await _eFlowSyncRepository.GetEFlowExternalId(entityName, primaryKeyJson); + if (externalId != null) + { + _externalIdCache.Add(obj, externalId); + } + } + + foreach (var child in parent.Children) + { + if (externalId == null) + { + if (child.DisplayName == obj.Name) + { + await _eFlowSyncRepository.AddEflowExternalId(entityName, primaryKeyJson, child.Id, cancellationToken); + _externalIdCache.Add(obj, child.Id); + + return child; + } + } + else + { + if (child.Id == externalId) + { + return child; + } + } + } + + //could not find the child, so we will need to add it here. + var newCategory = new CategoryInfo + { + ParentId = parent.Id, + Hostname = parent.Hostname, + Id = Guid.NewGuid().ToString("N").Left(16), + DisplayName = obj.Name + }; + + await _eFlowCategories.PostCategory(newCategory); + parent.Children.Add(newCategory); + _externalIdCache.Add(obj, newCategory.Id); + + return newCategory; + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/CategoryInfo.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/CategoryInfo.cs new file mode 100644 index 0000000..2e8bca2 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/CategoryInfo.cs @@ -0,0 +1,16 @@ +namespace e_suite.Service.EFlowSync.EflowAPI; + +public class CategoryInfo +{ + public string Hostname { get; set; } = string.Empty; + + public string Id { get; set; } = string.Empty; + + public string ParentId { get; set; } = string.Empty; + + public string DisplayName { get; set; } = string.Empty; + + public List Children { get; set; } = []; + + public DateTimeOffset? Deleted { get; set; } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/EFlowApiBase.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/EFlowApiBase.cs new file mode 100644 index 0000000..af718c0 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/EFlowApiBase.cs @@ -0,0 +1,84 @@ +using System.Net.Http.Headers; +using e_suite.API.Common.extensions; +using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; + +namespace e_suite.Service.EFlowSync.EflowAPI; + +public class EFlowApiBase : IFlowApi +{ + protected readonly IConfiguration _configuration; + + public EFlowApiBase(IConfiguration configuration) + { + _configuration = configuration; + } + + private HttpClient? _client; + private string _baseAddress = null!; + + protected HttpClient Client + { + get + { + if (_client == null) + { + _client = CreateHttpClient().GetAwaiter().GetResult(); + } + return _client; + + } + } + + private string BaseAddress + { + get + { + if (_baseAddress == null) + { + var eFlowServer = _configuration.GetConfigValue($"EflowAPI_SERVER", $"EflowAPI:Server", ""); + if (string.IsNullOrEmpty(eFlowServer)) + { + throw new Exception("EFlow Server not configured"); + } + + _baseAddress = eFlowServer; + } + + return _baseAddress; + } + } + + public string ApiKey { get; set; } = string.Empty; + + private async Task GetToken() + { + HttpClient client = new HttpClient(); + client.BaseAddress = new Uri(BaseAddress); + string grant_type = "password"; + string client_id = ApiKey; + + var form = new Dictionary + { + {"grant_type", grant_type}, + {"client_id", client_id} + }; + + HttpResponseMessage tokenResponse = await client.PostAsync("oauth2/token", new FormUrlEncodedContent(form)); + var jsonContent = await tokenResponse.Content.ReadAsStringAsync(); + var token = JsonConvert.DeserializeObject(jsonContent); + return token; + } + + protected async Task CreateHttpClient() + { + var token = await GetToken(); + if (token == null) + throw new NullReferenceException("unable to get token from e-flow"); + + HttpClient client = new HttpClient(); + client.BaseAddress = new Uri(BaseAddress); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token.AccessToken); + return client; + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/EFlowCategories.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/EFlowCategories.cs new file mode 100644 index 0000000..e3225be --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/EFlowCategories.cs @@ -0,0 +1,132 @@ +using System.Text; +using System.Text.Json; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.EFlowSync.EflowAPI; + +public class DeleteArgs +{ + public string UserName { get; set; } = string.Empty; + public string Reason { get; set; } = string.Empty; + public bool Cascade { get; set; } +} + +public class RestoreArgs +{ + public string Username { get; set; } = string.Empty; + public string Reason { get; set; } = string.Empty; + public bool Cascade { get; set; } +} + +public class UpdateCategoryArgs +{ + public string Id { get; set; } = string.Empty; + public string CategoryName { get; set; } = string.Empty; +} + +public class EFlowCategories : EFlowApiBase, IEFlowCategories +{ + private readonly string _ePrintUser = "e-print"; + + public EFlowCategories(IConfiguration configuration) : base(configuration) + { + } + + public async Task GetCategories(string categoryId) + { + var address = $"api/v1/categories/{categoryId}"; + + var result = await Client.GetAsync(address); + result.EnsureSuccessStatusCode(); + + var jsonString = await result.Content.ReadAsStringAsync(); + var jsonBytes = Encoding.ASCII.GetBytes(jsonString); + var endResult = JsonSerializer.Deserialize(jsonBytes); + return endResult!; + } + + public async Task PostCategory(CategoryInfo category) + { + var address = $"api/v1/categories"; + + var form = new Dictionary + { + { "Id", category.Id }, + { "ParentId", category.ParentId }, + { "CategoryName", category.DisplayName } + + }; + + var result = await Client.PostAsync(address, new FormUrlEncodedContent(form)); + result.EnsureSuccessStatusCode(); + } + + public async Task RestoreCategory(CategoryInfo category) + { + var address = $"api/v1/restore?id={Uri.EscapeDataString(category.Id)}"; + + var deleteArgs = new RestoreArgs + { + Username = _ePrintUser, + Reason = "e-Print Synchronisation", + Cascade = false + }; + + var request = new HttpRequestMessage + { + Method = HttpMethod.Post, + RequestUri = new Uri(address, UriKind.Relative), + Content = new StringContent(JsonSerializer.Serialize(deleteArgs), Encoding.UTF8, "application/json") + + }; + + var result = await Client.SendAsync(request); + result.EnsureSuccessStatusCode(); + } + + public async Task UpdateCategory(CategoryInfo category) + { + var address = $"api/v1/categories"; + + var deleteArgs = new UpdateCategoryArgs + { + Id = category.Id, + CategoryName = category.DisplayName + }; + + var request = new HttpRequestMessage + { + Method = HttpMethod.Put, + RequestUri = new Uri(address, UriKind.Relative), + Content = new StringContent(JsonSerializer.Serialize(deleteArgs), Encoding.UTF8, "application/json") + + }; + + var result = await Client.SendAsync(request); + result.EnsureSuccessStatusCode(); + } + + public async Task DeleteCategory(CategoryInfo category) + { + var address = $"api/v1/categories?id={Uri.EscapeDataString(category.Id)}"; + + var deleteArgs = new DeleteArgs + { + UserName = _ePrintUser, + Reason = "e-Print Synchronisation", + Cascade = true + }; + + var request = new HttpRequestMessage + { + Method = HttpMethod.Delete, + RequestUri = new Uri(address, UriKind.Relative), + Content = new StringContent(JsonSerializer.Serialize(deleteArgs), Encoding.UTF8, "application/json") + + }; + + var result = await Client.SendAsync(request); + result.EnsureSuccessStatusCode(); + } + +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/IEFlowCategories.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/IEFlowCategories.cs new file mode 100644 index 0000000..79e843b --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/IEFlowCategories.cs @@ -0,0 +1,10 @@ +namespace e_suite.Service.EFlowSync.EflowAPI; + +public interface IEFlowCategories : IFlowApi +{ + Task GetCategories(string categoryId); + Task PostCategory(CategoryInfo category); + Task DeleteCategory(CategoryInfo category); + Task RestoreCategory(CategoryInfo category); + Task UpdateCategory(CategoryInfo category); +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/IFlowApi.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/IFlowApi.cs new file mode 100644 index 0000000..ddf7eb6 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/IFlowApi.cs @@ -0,0 +1,5 @@ +namespace e_suite.Service.EFlowSync.EflowAPI; + +public interface IFlowApi { + string ApiKey { get; set; } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/Token.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/Token.cs new file mode 100644 index 0000000..804e044 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/EflowAPI/Token.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace e_suite.Service.EFlowSync.EflowAPI; + +public class Token +{ + [JsonProperty("access_token")] + public string AccessToken { get; set; } = null!; + + [JsonProperty("token_type")] + public string TokenType { get; set; } = null!; + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("refresh_token")] + public string RefreshToken { get; set; } = null!; +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Extensions/ObjectExtensions.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..cce435d --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Extensions/ObjectExtensions.cs @@ -0,0 +1,32 @@ +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; + +namespace e_suite.Service.EFlowSync.Extensions; + +public static class ObjectExtensions +{ + public static Dictionary PrimaryKeyDictionary(this Type type, object obj) + { + var primaryKey = new Dictionary(); + + var properties = type.GetProperties(); + foreach (var property in properties) + { + var isPrimaryKey = property.CustomAttributes.SingleOrDefault(x => x.AttributeType == typeof(KeyAttribute)) != null; + if (isPrimaryKey) + { + primaryKey[property.Name] = property.GetValue(obj); + } + } + + return primaryKey; + } + + public static string ToPrimaryKeyJson( this Dictionary primaryKey ) + { + return JsonConvert.SerializeObject(primaryKey, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Extensions/StringExtensions.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Extensions/StringExtensions.cs new file mode 100644 index 0000000..f4521b9 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Extensions/StringExtensions.cs @@ -0,0 +1,16 @@ +namespace e_suite.Service.EFlowSync.Extensions; + +public static class StringExtensions +{ + public static string Left(this string value, int maxLength) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + maxLength = Math.Abs(maxLength); + + return value.Length <= maxLength ? value : value.Substring(0, maxLength); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/GlobalSuppressions.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/IocRegistration.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/IocRegistration.cs new file mode 100644 index 0000000..f5ee4b0 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/IocRegistration.cs @@ -0,0 +1,16 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.Service.EFlowSync.EflowAPI; +using e_suite.Service.EFlowSync.Repository; + +namespace e_suite.Service.EFlowSync; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/EFlowSyncRepository.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/EFlowSyncRepository.cs new file mode 100644 index 0000000..d1162b2 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/EFlowSyncRepository.cs @@ -0,0 +1,46 @@ +using System.Security.Cryptography.X509Certificates; +using Dapper; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Miscellaneous; + +namespace e_suite.Service.EFlowSync.Repository; + +public enum externalSystems +{ + eflow = 1 +} + +public class EFlowSyncRepository : RepositoryBase, IEFlowSyncRepository +{ + public EFlowSyncRepository(IEsuiteDatabaseDbContext esuiteDatabaseDbContext) : base(esuiteDatabaseDbContext) + { + } + + //public async Task> GetPrintSpecListForDomain(Guid domainGuid) + //{ + // var parameters = new { domainGuid = domainGuid.ToString() }; + // var getPrintSpecificationCategoryInformation = await File.ReadAllTextAsync("Resources/Scripts/GetPrintSpecificationCategoryInformation.sql"); + // return await DbLoggerCategory.Database.Connection.QueryAsync(getPrintSpecificationCategoryInformation, parameters); + //} + public Task GetEFlowExternalId(string entityName, string primaryKeyJson) + { + return Task.FromResult(DatabaseDbContext.ExternalKeys + .Where(x => x.ExternalSystemId == (long)externalSystems.eflow + && x.EntityName == entityName + && x.PrimaryKey == primaryKeyJson).Select(x => x.ExternalId).SingleOrDefault()); + } + + public async Task AddEflowExternalId(string entityName, string primaryKeyJson, string childId, CancellationToken cancellationToken) + { + var externalKey = new ExternalKey + { + ExternalSystemId = (long)externalSystems.eflow, + EntityName = entityName, + PrimaryKey = primaryKeyJson, + ExternalId = childId + }; + + await DatabaseDbContext.ExternalKeys.AddAsync(externalKey, cancellationToken); + await DatabaseDbContext.NoAuditSaveChangesAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/IEFlowSyncRepository.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/IEFlowSyncRepository.cs new file mode 100644 index 0000000..a82a54e --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/IEFlowSyncRepository.cs @@ -0,0 +1,10 @@ +using System.Threading; + +namespace e_suite.Service.EFlowSync.Repository; + +public interface IEFlowSyncRepository +{ + //Task> GetPrintSpecListForDomain(Guid domainGuid); + Task GetEFlowExternalId(string entityName, string primaryKeyJson); + Task AddEflowExternalId(string entityName, string primaryKeyJson, string childId, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/PrintSpecificationCategoryInformation.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/PrintSpecificationCategoryInformation.cs new file mode 100644 index 0000000..d1f7713 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/PrintSpecificationCategoryInformation.cs @@ -0,0 +1,10 @@ +namespace e_suite.Service.EFlowSync.Repository; + +public class PrintSpecificationCategoryInformation +{ + public string OrganisationName { get; set; } = string.Empty; + public string SiteName { get; set; } = string.Empty; + public string PrintProcess { get; set; } = string.Empty; + public string SpecificationName { get; set; } = string.Empty; + public DateTimeOffset LastUpdated { get; set; } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/SqlRepositoryBase.cs b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/SqlRepositoryBase.cs new file mode 100644 index 0000000..d70e502 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Repository/SqlRepositoryBase.cs @@ -0,0 +1,24 @@ +using System.Data.Common; +using e_suite.Database.SqlServer; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.EFlowSync.Repository; + +public class SqlRepositoryBase : IDisposable +{ + protected DbConnection Connection { get; } + + public SqlRepositoryBase(IConfiguration configuration) + { + var connectionString = ESuiteDatabaseExtension.BuildConnectionString(configuration); + + Connection = new SqlConnection(connectionString); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + Connection.Close(); + } +} \ No newline at end of file diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Resources/Scripts/GetPrintSpecificationCategoryInformation.sql b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Resources/Scripts/GetPrintSpecificationCategoryInformation.sql new file mode 100644 index 0000000..0a6bda9 --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/Resources/Scripts/GetPrintSpecificationCategoryInformation.sql @@ -0,0 +1,53 @@ +with cte as ( +select + organisation.Name as OrganisationName, + site.Name as SiteName, + spec.Name as SpecificationName, + fi.Id as FormInstanceId, + ( + select max( result.LastUpdated ) + From ( + select organisation.LastUpdated as LastUpdated + union all + select site.LastUpdated as LastUpdated + union all + select spec.LastUpdated as LastUpdated + union all + select fi.LastUpdated as LastUpdated) as result + ) as LastUpdated, + ( + select ffi.DisplayValue + from Forms.FormFieldInstances as ffi + join CustomFields.CustomFields as cf + on cf.Id = ffi.CustomFieldId + and cf.Guid = '45821C2D-9D6E-4C82-AC57-965755960422' --Domain cf guid + where ffi.FormInstanceId = fi.Id + and ffi.Value = @domainGuid + ) as DomainGuid +from Printer.Specifications as spec +join Printer.Sites as site + on site.Id = spec.SiteId +join printer.Organisations as organisation + on organisation.Id = site.OrganisationId +join Forms.FormInstances as fi + on fi.Id = spec.FormInstanceId + and fi.Deleted = 0 +) +select + cte.OrganisationName, + cte.SiteName, + cte.SpecificationName, + PrintProcess.DisplayValue as PrintProcess, + cte.LastUpdated +from cte +cross apply ( + select + ffi.DisplayValue + from Forms.FormFieldInstances as ffi + join CustomFields.CustomFields as cf + on cf.Id = ffi.CustomFieldId + and cf.Guid = '1F2AEB33-DA9C-4563-BE88-177F485E789B' --Print Process cf Guid + where ffi.FormInstanceId = cte.FormInstanceId) as PrintProcess +where DomainGuid is not null +order by + OrganisationName, SiteName, SpecificationName diff --git a/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.csproj b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.csproj new file mode 100644 index 0000000..b508e0c --- /dev/null +++ b/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync/e-suite.Service.EFlowSync.csproj @@ -0,0 +1,30 @@ + + + + net10.0 + e_suite.Service.EFlowSync + enable + enable + + + + + + + + + Always + + + + + + + + + + + + + + diff --git a/e-suite.Service.EFlowSync/nuget.config b/e-suite.Service.EFlowSync/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Service.EFlowSync/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.Mail/.gitattributes b/e-suite.Service.Mail/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Service.Mail/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Service.Mail/.gitignore b/e-suite.Service.Mail/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Service.Mail/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Service.Mail/.runsettings b/e-suite.Service.Mail/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Service.Mail/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.Mail/README.md b/e-suite.Service.Mail/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Service.Mail/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Service.Mail/azure-pipelines.yml b/e-suite.Service.Mail/azure-pipelines.yml new file mode 100644 index 0000000..ce2f404 --- /dev/null +++ b/e-suite.Service.Mail/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Service.Mail/e-suite.Service.Mail.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '70' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/MailService/RequestEMailAsyncUnitTests.cs b/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/MailService/RequestEMailAsyncUnitTests.cs new file mode 100644 index 0000000..d5ceba3 --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/MailService/RequestEMailAsyncUnitTests.cs @@ -0,0 +1,162 @@ +using e_suite.API.Common.exceptions; +using e_suite.Database.Core.Tables.Mail; +using e_suite.Database.Core.Tables.UserManager; +using eSuite.Core.MailService; +using Moq; +using NUnit.Framework; +using System.Net; +using System.Net.Mail; +using System.Threading; +using e_suite.Service.Mail.Facade; + +namespace e_suite.Service.Mail.UnitTests.MailService; + +[TestFixture] +public class RequestEMailAsyncUnitTests : MailServiceTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task RequestEMailAsync_WhenNoDestination_DoesNotSendAnyMails() + { + //Arrange + var mailRequest = new MailRequest(); + + //Act + await mailService.RequestEMailAsync(mailRequest, CancellationToken.None); + + //Assert + MailClientFactoryMock.Verify( x => x.CreateSmtpClient( It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public void RequestEMailAsync_EmailDestinationNotFound_ThrowsExpectedNotFoundException() + { + //Arrange + var mailRequest = new MailRequest(); + var user = new User + { + Email = "test@test.test", + FirstName = "Testy", + LastName = "McTester" + }; + + mailRequest.To.Add(user); + mailRequest.EmailType = MailType.ConfirmEmailAddress; + mailRequest.Parameters.Add("url", "http://test.com/emailsstuff/testing"); + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await mailService.RequestEMailAsync(mailRequest, CancellationToken.None); + }); + Assert.That(result!.Message, Is.EqualTo($"Unable to find user for e-mail {user.Email}")); + } + + [Test] + public void RequestEMailAsync_EmailDestinationFound_AttemptsToPrepareMessageBody() + { + //Arrange + var mailRequest = new MailRequest(); + var user = new User + { + Email = "test@test.test", + FirstName = "Testy", + LastName = "McTester", + DomainId = 1 + }; + + mailRequest.To.Add(user); + mailRequest.EmailType = MailType.ConfirmEmailAddress; + mailRequest.Parameters.Add("url", "http://test.com/emailsstuff/testing"); + + UserManagerRepositoryMock.Setup(x => x.GetUserByEmail(user.Email, It.IsAny())).ReturnsAsync(user); + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await mailService.RequestEMailAsync(mailRequest, CancellationToken.None); + }); + MailServiceRepositoryMock.Verify( x => x.GetMailTemplate(It.IsAny(), It.IsAny(), It.IsAny()), Times.AtLeastOnce); + } + + [Test] + public async Task RequestEMailAsync_CanCreateEmail_SendsEmailSuccessfully() + { + //Arrange + var mailRequest = new MailRequest(); + var user = new User + { + Email = "test@test.test", + FirstName = "Testy", + LastName = "McTester", + DomainId = 1 + }; + + mailRequest.To.Add(user); + mailRequest.EmailType = MailType.ConfirmEmailAddress; + mailRequest.Parameters.Add("url", "http://test.com/emailsstuff/testing"); + + UserManagerRepositoryMock.Setup(x => x.GetUserByEmail(user.Email, It.IsAny())).ReturnsAsync(user); + + var mailTemplate = new MailTemplate(); + + MailServiceRepositoryMock.Setup(x => x.GetMailTemplate(It.IsAny(), mailRequest.EmailType, It.IsAny())).ReturnsAsync(mailTemplate); + + var smtpClientMock = new Mock(); + + MailClientFactoryMock.Setup(x => x.CreateSmtpClient(It.IsAny(), It.IsAny())).Returns(smtpClientMock.Object); + + //Act + await mailService.RequestEMailAsync(mailRequest, CancellationToken.None); + + //Assert + smtpClientMock.Verify( x=> x.SendMailAsync(It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public void RequestEMailAsync_WhenEmailClientFailsToSend_ThrowsExceptionFromMailClient() + { + //Arrange + var mailRequest = new MailRequest(); + var user = new User + { + Email = "test@test.test", + FirstName = "Testy", + LastName = "McTester", + DomainId = 1 + }; + + mailRequest.To.Add(user); + mailRequest.EmailType = MailType.ConfirmEmailAddress; + mailRequest.Parameters.Add("url", "http://test.com/emailsstuff/testing"); + + UserManagerRepositoryMock.Setup(x => x.GetUserByEmail(user.Email, It.IsAny())).ReturnsAsync(user); + + var mailTemplate = new MailTemplate(); + + MailServiceRepositoryMock.Setup(x => x.GetMailTemplate(It.IsAny(), mailRequest.EmailType, It.IsAny())).ReturnsAsync(mailTemplate); + + var smtpClientMock = new Mock(); + + MailClientFactoryMock.Setup(x => x.CreateSmtpClient(It.IsAny(), It.IsAny())).Returns(smtpClientMock.Object); + + smtpClientMock.Setup(x => x.SendMailAsync(It.IsAny(), It.IsAny())) + .Throws(new Exception("Test error")); + + //Assert + var result = Assert.ThrowsAsync(async () => + { + //Act + await mailService.RequestEMailAsync(mailRequest, CancellationToken.None); + }); + + Assert.That(result!.Message, Is.EqualTo("Test error")); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/MailServiceTestBase.cs b/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/MailServiceTestBase.cs new file mode 100644 index 0000000..af29da9 --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/MailServiceTestBase.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using e_suite.API.Common.repository; +using e_suite.Service.Mail.Facade; +using e_suite.UnitTestCore; +using eSuite.Core.MailService; +using Moq; + +namespace e_suite.Service.Mail.UnitTests; + +public class MailServiceTestBase : TestBase +{ + protected IConfiguration configuration = null!; + protected IMailService mailService = null!; + protected Mock UserManagerRepositoryMock = null!; + protected Mock MailServiceRepositoryMock = null!; + protected Mock MailClientFactoryMock = null!; + + public override async Task Setup() + { + await base.Setup(); + + var imMemorySettings = new Dictionary + { + { "Smtp:Username", "TestUsername" }, + { "Smtp:Password", "It is a secret" }, + { "Smtp:FromAddress", "testSender@test.com"} + }; + + configuration = new ConfigurationBuilder() + .AddInMemoryCollection(imMemorySettings!) + .Build(); + + UserManagerRepositoryMock = new Mock(); + MailServiceRepositoryMock = new Mock(); + MailClientFactoryMock = new Mock(); + + mailService = new Mail.MailService(configuration, UserManagerRepositoryMock.Object, + MailServiceRepositoryMock.Object, MailClientFactoryMock.Object); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/e-suite.Service.Mail.UnitTests.csproj b/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/e-suite.Service.Mail.UnitTests.csproj new file mode 100644 index 0000000..5969e7e --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail.UnitTests/e-suite.Service.Mail.UnitTests.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + e_suite.Service.Mail.UnitTests + enable + enable + + + + + + + + + + + + + + + + diff --git a/e-suite.Service.Mail/e-suite.Service.Mail.sln b/e-suite.Service.Mail/e-suite.Service.Mail.sln new file mode 100644 index 0000000..699e839 --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.Mail", "e-suite.Service.Mail\e-suite.Service.Mail.csproj", "{EAF0AAF2-EA05-4BA5-A0C3-CFB525965CAD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{B78CBF02-9336-4759-A06A-AB0F2CCF6685}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{69CD29F3-1602-4435-A604-483644AA45D6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Service.Mail.UnitTests", "e-suite.Service.Mail.UnitTests\e-suite.Service.Mail.UnitTests.csproj", "{CB856EA9-5FE5-42E8-9F73-A0D405D8473D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EAF0AAF2-EA05-4BA5-A0C3-CFB525965CAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAF0AAF2-EA05-4BA5-A0C3-CFB525965CAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAF0AAF2-EA05-4BA5-A0C3-CFB525965CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAF0AAF2-EA05-4BA5-A0C3-CFB525965CAD}.Release|Any CPU.Build.0 = Release|Any CPU + {CB856EA9-5FE5-42E8-9F73-A0D405D8473D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB856EA9-5FE5-42E8-9F73-A0D405D8473D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB856EA9-5FE5-42E8-9F73-A0D405D8473D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB856EA9-5FE5-42E8-9F73-A0D405D8473D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {69CD29F3-1602-4435-A604-483644AA45D6} = {B78CBF02-9336-4759-A06A-AB0F2CCF6685} + {CB856EA9-5FE5-42E8-9F73-A0D405D8473D} = {69CD29F3-1602-4435-A604-483644AA45D6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0A0A4DF8-F09A-4DBF-9936-B1A799ADBC89} + EndGlobalSection +EndGlobal diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/Facade/ISmtpClient.cs b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/ISmtpClient.cs new file mode 100644 index 0000000..90e6727 --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/ISmtpClient.cs @@ -0,0 +1,12 @@ +using System.Net; +using System.Net.Mail; + +namespace e_suite.Service.Mail.Facade; + +public interface ISmtpClient : IDisposable +{ + ICredentialsByHost? Credentials { get; set; } + bool EnableSsl { get; set; } + int Timeout { get; set; } + Task SendMailAsync(MailMessage message, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/Facade/ISmtpClientFactory.cs b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/ISmtpClientFactory.cs new file mode 100644 index 0000000..d723e7f --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/ISmtpClientFactory.cs @@ -0,0 +1,6 @@ +namespace e_suite.Service.Mail.Facade; + +public interface ISmtpClientFactory +{ + ISmtpClient CreateSmtpClient(string? host, int port); +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/Facade/SmtpClientFacade.cs b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/SmtpClientFacade.cs new file mode 100644 index 0000000..ca73b6d --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/SmtpClientFacade.cs @@ -0,0 +1,52 @@ +using System.Net; +using System.Net.Mail; + +namespace e_suite.Service.Mail.Facade; + +public class SmtpClientFacade : ISmtpClient +{ + private SmtpClient? _client; + + public SmtpClientFacade() + { + _client = new SmtpClient(); + } + + public SmtpClientFacade(string? host, int port) + { + _client = new SmtpClient(host, port); + } + + public void Dispose() + { + if (_client == null) + return; + + GC.SuppressFinalize(this); + _client.Dispose(); + _client = null!; + } + + public ICredentialsByHost? Credentials + { + get => _client!.Credentials; + set => _client!.Credentials = value; + } + + public bool EnableSsl + { + get => _client!.EnableSsl; + set => _client!.EnableSsl = value; + } + + public int Timeout + { + get => _client!.Timeout; + set => _client!.Timeout = value; + } + + public async Task SendMailAsync(MailMessage message, CancellationToken cancellationToken) + { + await _client!.SendMailAsync(message, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/Facade/SmtpClientFactory.cs b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/SmtpClientFactory.cs new file mode 100644 index 0000000..f2f55cd --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/Facade/SmtpClientFactory.cs @@ -0,0 +1,9 @@ +namespace e_suite.Service.Mail.Facade; + +public class SmtpClientFactory : ISmtpClientFactory +{ + public ISmtpClient CreateSmtpClient(string? host, int port) + { + return new SmtpClientFacade(host, port); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/Helper/ConfigurationHelper.cs b/e-suite.Service.Mail/e-suite.Service.Mail/Helper/ConfigurationHelper.cs new file mode 100644 index 0000000..47dffbb --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/Helper/ConfigurationHelper.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Mail.Helper; + +public static class ConfigurationHelper +{ + public static T? GetConfigValue( this IConfiguration configuration, string environmentVariable, string key, T defaultValue ) + { + var envVariable = Environment.GetEnvironmentVariable(environmentVariable); + + if (!string.IsNullOrWhiteSpace(envVariable) ) + return (T?)Convert.ChangeType(envVariable, typeof(T)); + + return configuration.GetValue(key, defaultValue); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/IocRegistration.cs b/e-suite.Service.Mail/e-suite.Service.Mail/IocRegistration.cs new file mode 100644 index 0000000..f00818e --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/IocRegistration.cs @@ -0,0 +1,17 @@ +using Autofac; +using e_suite.API.Common.repository; +using e_suite.Service.Mail.Facade; +using e_suite.Service.Mail.repository; +using eSuite.Core.MailService; + +namespace e_suite.Service.Mail; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/MailService.cs b/e-suite.Service.Mail/e-suite.Service.Mail/MailService.cs new file mode 100644 index 0000000..a379ec2 --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/MailService.cs @@ -0,0 +1,163 @@ +using System.Net; +using System.Net.Mail; +using System.Net.Mime; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.repository; +using e_suite.Service.Mail.Facade; +using e_suite.Service.Mail.Helper; +using eSuite.Core.MailService; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Mail; + +public class MailService : IMailService +{ + private readonly IConfiguration _configuration; + private readonly IUserManagerRepository _userManagerRepository; + private readonly IMailServiceRepository _mailServiceRepository; + private readonly ISmtpClientFactory _smtpClientFactory; + const long SunStrategyDomainId = 1; + + public MailService(IConfiguration configuration, IUserManagerRepository userManagerRepository, IMailServiceRepository mailServiceRepository, ISmtpClientFactory smtpClientFactory) + { + _configuration = configuration; + _userManagerRepository = userManagerRepository; + _mailServiceRepository = mailServiceRepository; + _smtpClientFactory = smtpClientFactory; + } + + public async Task RequestEMailAsync(MailRequest emailRequest, CancellationToken cancellationToken) + { + var username = _configuration.GetConfigValue("MAIL_USERNAME", "Smtp:Username", string.Empty); + var host = _configuration.GetConfigValue("MAIL_SERVER", "Smtp:Server", "defaultmailserver"); + + var port = _configuration.GetConfigValue("MAIL_PORT", "Smtp:Port", 25); + var fromAddress = _configuration.GetConfigValue("MAIL_ADDRESS", "Smtp:FromAddress", "defaultFromAddress"); + var fromDisplayName = _configuration.GetConfigValue("MAIL_DISPLAY_NAME","Smtp:FromDisplayName", "eSuite MailService"); + + foreach (var address in emailRequest.To) + { + var message = new MailMessage + { + Body = null, + BodyEncoding = null, + BodyTransferEncoding = TransferEncoding.QuotedPrintable, + DeliveryNotificationOptions = DeliveryNotificationOptions.None, + From = new MailAddress(fromAddress!, fromDisplayName), + HeadersEncoding = null, + IsBodyHtml = false, + Priority = MailPriority.Normal, + Sender = null!, + Subject = null, + SubjectEncoding = null, + }; + + var user = await _userManagerRepository.GetUserByEmail(address.Email, cancellationToken) ?? + throw new NotFoundException($"Unable to find user for e-mail {address.Email}"); + + message.To.Add(new MailAddress(address.Email, address.DisplayName)); + + await PrepareMessageBody(message, emailRequest, user.DomainId, cancellationToken); + + using var client = _smtpClientFactory.CreateSmtpClient(host, port); + + if (!string.IsNullOrEmpty(username)) + { + var password = _configuration.GetConfigValue("MAIL_PASSWORD", "Smtp:Password", string.Empty); + client.Credentials = new NetworkCredential(username, password); + } + + client.EnableSsl = _configuration.GetValue("Smtp:EnableSSL", false); + client.Timeout = _configuration.GetValue("Smtp:timeout", 30000); + +#pragma warning disable SYSLIB0014 + //There is no option be to use the ServicePointManager at the moment. + ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack!; +#pragma warning restore SYSLIB0014 + + try + { + await client.SendMailAsync(message, cancellationToken); + //todo add audit record here to say that email of mailtype has been sent to user. + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + } + + private async Task PrepareMessageBody(MailMessage message, MailRequest emailRequest, long domainId, + CancellationToken cancellationToken) + { + message.IsBodyHtml = true; + + var mailTemplate = + await _mailServiceRepository.GetMailTemplate(domainId, emailRequest.EmailType, cancellationToken) ?? await _mailServiceRepository.GetMailTemplate(SunStrategyDomainId, emailRequest.EmailType, + cancellationToken) ?? + throw new NotImplementedException($"{emailRequest.EmailType} not implemented"); + + message.Subject = mailTemplate.Subject; + message.Body = $"{mailTemplate.TemplateDefinition}"; + + SubstituteParameters(message, emailRequest); + + } + + private static void SubstituteParameters(MailMessage message, MailRequest emailRequest) + { + foreach (var parameter in emailRequest.Parameters) + message.Body = message.Body.Replace($"${parameter.Key}", parameter.Value, StringComparison.InvariantCultureIgnoreCase); + } + + /// + /// https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633677(v=exchg.80)?redirectedfrom=MSDN + /// + /// + /// + /// + /// + /// + private static bool CertificateValidationCallBack( + object sender, + System.Security.Cryptography.X509Certificates.X509Certificate certificate, + System.Security.Cryptography.X509Certificates.X509Chain chain, + System.Net.Security.SslPolicyErrors sslPolicyErrors) + { + // If the certificate is a valid, signed certificate, return true. + if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None) return true; + + // If there are errors in the certificate chain, look at each error to determine the cause. + if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0) + { + if (chain != null && chain.ChainStatus != null) + foreach (var status in chain.ChainStatus) + if (certificate.Subject == certificate.Issuer && + status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags + .UntrustedRoot) + { + // Self-signed certificates with an untrusted root are valid. + continue; + } + else + { + if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags + .NoError) + // If there are any other errors in the certificate chain, the certificate is invalid, + // so the method returns false. + return false; + } + + // When processing reaches this line, the only errors in the certificate chain are + // untrusted root errors for self-signed certificates. These certificates are valid + // for default Exchange server installations, so return true. + return true; + } + else + { + // In all other cases, return false. + return false; + } + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/e-suite.Service.Mail.csproj b/e-suite.Service.Mail/e-suite.Service.Mail/e-suite.Service.Mail.csproj new file mode 100644 index 0000000..70517b3 --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/e-suite.Service.Mail.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.Service.Mail + enable + enable + + + + + + + + + + + + diff --git a/e-suite.Service.Mail/e-suite.Service.Mail/repository/MailServiceRepository.cs b/e-suite.Service.Mail/e-suite.Service.Mail/repository/MailServiceRepository.cs new file mode 100644 index 0000000..ffe37bb --- /dev/null +++ b/e-suite.Service.Mail/e-suite.Service.Mail/repository/MailServiceRepository.cs @@ -0,0 +1,20 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Mail; +using eSuite.Core.MailService; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Service.Mail.repository; + +public class MailServiceRepository : RepositoryBase, IMailServiceRepository +{ + public MailServiceRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) + { + } + + public async Task GetMailTemplate(long domainId, MailType emailRequestEmailType, CancellationToken cancellationToken) + { + return await DatabaseDbContext.MailTemplates.SingleOrDefaultAsync(x => + !x.Deleted && x.DomainId == domainId && x.MailType == emailRequestEmailType, cancellationToken); + } +} \ No newline at end of file diff --git a/e-suite.Service.Mail/nuget.config b/e-suite.Service.Mail/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Service.Mail/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.Performance/.gitattributes b/e-suite.Service.Performance/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Service.Performance/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Service.Performance/.gitignore b/e-suite.Service.Performance/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Service.Performance/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Service.Performance/README.md b/e-suite.Service.Performance/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Service.Performance/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Service.Performance/azure-pipelines.yml b/e-suite.Service.Performance/azure-pipelines.yml new file mode 100644 index 0000000..5f4b563 --- /dev/null +++ b/e-suite.Service.Performance/azure-pipelines.yml @@ -0,0 +1,133 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Service.Performance/e-suite.Service.Performance.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '10' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Service.Performance/e-suite.Service.Performance.UnitTests/e-suite.Service.Performance.UnitTests.csproj b/e-suite.Service.Performance/e-suite.Service.Performance.UnitTests/e-suite.Service.Performance.UnitTests.csproj new file mode 100644 index 0000000..3dd320f --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance.UnitTests/e-suite.Service.Performance.UnitTests.csproj @@ -0,0 +1,32 @@ + + + + net10.0 + e_suite.Service.Performance.UnitTests + enable + enable + + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/e-suite.Service.Performance/e-suite.Service.Performance.sln b/e-suite.Service.Performance/e-suite.Service.Performance.sln new file mode 100644 index 0000000..402a7fe --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.Performance", "e-suite.Service.Performance\e-suite.Service.Performance.csproj", "{0126E558-0467-4490-B497-ABE0AF8D4B34}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.Performance.UnitTests", "e-suite.Service.Performance.UnitTests\e-suite.Service.Performance.UnitTests.csproj", "{0004A7CB-510E-4761-B707-C4F45FA0B4FA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{05E2FB6E-6874-44A3-9707-AD73375DD44A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{90027CE1-A05F-4C29-BF34-6F326E65709D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0126E558-0467-4490-B497-ABE0AF8D4B34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0126E558-0467-4490-B497-ABE0AF8D4B34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0126E558-0467-4490-B497-ABE0AF8D4B34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0126E558-0467-4490-B497-ABE0AF8D4B34}.Release|Any CPU.Build.0 = Release|Any CPU + {0004A7CB-510E-4761-B707-C4F45FA0B4FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0004A7CB-510E-4761-B707-C4F45FA0B4FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0004A7CB-510E-4761-B707-C4F45FA0B4FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0004A7CB-510E-4761-B707-C4F45FA0B4FA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0004A7CB-510E-4761-B707-C4F45FA0B4FA} = {90027CE1-A05F-4C29-BF34-6F326E65709D} + {90027CE1-A05F-4C29-BF34-6F326E65709D} = {05E2FB6E-6874-44A3-9707-AD73375DD44A} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3876F872-78CC-40F1-A2F3-0E2820BE27B5} + EndGlobalSection +EndGlobal diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerfomanceMonitorMiddleware.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerfomanceMonitorMiddleware.cs new file mode 100644 index 0000000..58f139d --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerfomanceMonitorMiddleware.cs @@ -0,0 +1,55 @@ +using e_suite.Service.Performance.Interfaces; +using eSuite.Core.Clock; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Caching.Memory; + +namespace e_suite.Service.Performance.Extensions.Web; + +public class PerformanceMonitorMiddleware +{ + private readonly RequestDelegate _next; + private readonly IPerformanceReportProcessor _performanceReportProcessor; + private readonly IMemoryCache _memoryCache; + private readonly IClock _clock; + + public PerformanceMonitorMiddleware(RequestDelegate next, IPerformanceReportProcessor performanceReportProcessor, IMemoryCache memoryCache, IClock clock) + { + _next = next; + _performanceReportProcessor = performanceReportProcessor; + _memoryCache = memoryCache; + _clock = clock; + } + public async Task InvokeAsync(HttpContext context) + { + var routeData = context.GetRouteData(); + var traceId = context.TraceIdentifier; + var performanceReportRequest = new PerformanceCapture("Round Trip", _clock) + { + Host = context.Request.Host.Value!, + ControllerName = routeData.Values["controller"]?.ToString() ?? string.Empty, + ActionName = routeData.Values["action"]?.ToString() ?? string.Empty, + RequestType = context.Request.Method, + ActionParameters = (IDictionary)_memoryCache.Get("actionParams")! + }; + performanceReportRequest.Markers.AddMarker(nameof(InvokeAsync)); + _memoryCache.GetOrCreate(traceId, cacheEntry => + { + cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(10); + cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(50); + return performanceReportRequest; + }); + + await _next.Invoke(context); + + var performanceReportResponse = _memoryCache.Get(traceId); + if (performanceReportResponse != null) + { + performanceReportRequest.Markers.AddMarker($"{nameof(InvokeAsync)} Endeed"); + performanceReportResponse.Stopwatch.Stop(); + _memoryCache.Remove(traceId); + await _performanceReportProcessor.ProcessReportAsync(performanceReportResponse); + } + } + +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceActionParamMaperFilter.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceActionParamMaperFilter.cs new file mode 100644 index 0000000..b7bcfff --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceActionParamMaperFilter.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Caching.Memory; +namespace e_suite.Service.Performance.Extensions.Web; + +public class PerformanceActionParamMaperFilter : ActionFilterAttribute +{ + private readonly IMemoryCache _memoryCache; + + public PerformanceActionParamMaperFilter(IMemoryCache memoryCache) + { + _memoryCache = memoryCache; + } + + public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var traceId = context.HttpContext.TraceIdentifier; + var report = _memoryCache.Get(traceId); + + if (context.Filters.Any(f => f.GetType() == typeof(PerformanceMonitorFilterDisabler))) + { + var disabledRes = new Dictionary + { + { "DisabledFilter", "ActionsParams are disabled for this Action" } + }; + report!.ActionParameters = disabledRes; + } + else + { + report!.ActionParameters = context.ActionArguments!; + } + + _memoryCache.Set(traceId, report);//TODO Remove magic string + return base.OnActionExecutionAsync(context, next); + } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceMiddlewareExtensions.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceMiddlewareExtensions.cs new file mode 100644 index 0000000..724d900 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceMiddlewareExtensions.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Builder; + +namespace e_suite.Service.Performance.Extensions.Web; + +/// +/// Adds the Performance Moniotr to the Pipeline +/// Don`t Forget : to capcher ActionParameters the PerformanceActionParamMaperFilter must be added to the Filter pipeline +/// Note: When using try to add this delegate to the end of the pipline preferably right before the rauting delegate to get a more precise measurement +/// +public static class PerformanceMiddlewareExtensions +{ + public static IApplicationBuilder AddPerformanceMonitor(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} \ No newline at end of file diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceMonitorFilterDisabler.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceMonitorFilterDisabler.cs new file mode 100644 index 0000000..4ef4449 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/PerformanceMonitorFilterDisabler.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Mvc.Filters; + +namespace e_suite.Service.Performance.Extensions.Web; + +public class PerformanceMonitorFilterDisabler : ActionFilterAttribute +{ +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/WebBuilderExtensions.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/WebBuilderExtensions.cs new file mode 100644 index 0000000..23bc8d7 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Extensions/Web/WebBuilderExtensions.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace e_suite.Service.Performance.Extensions.Web; + +public static class WebBuilderExtensions +{ + public static void AddPerformanceMonitor(this WebApplicationBuilder builder) + { + builder.Services.AddControllers(options => + { + options.Filters.Add(); + }); + } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/GlobalSuppressions.cs b/e-suite.Service.Performance/e-suite.Service.Performance/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/PerformanceCache.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/PerformanceCache.cs new file mode 100644 index 0000000..378d7a4 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/PerformanceCache.cs @@ -0,0 +1,118 @@ +using e_suite.Service.Performance.Interfaces; + +namespace e_suite.Service.Performance.Implementations; + +public class PerformanceCache : IPerformanceCache +{ + public PerformanceCache() + { + + } + + private class RequestCache + { + private DateTimeOffset _expires; + private long cacheEntry; + + public RequestCache(long timeOutMs) + { + UpdateTimeoutCache(timeOutMs); + } + + public long? GetCacheValue() + { + if (_expires > DateTimeOffset.UtcNow) + return cacheEntry; + + return null; + } + + public void UpdateTimeoutCache(long timeOutMs) + { + _expires = DateTimeOffset.UtcNow.AddMinutes(5); + cacheEntry = timeOutMs; + } + } + + private class ActionCache + { + private Dictionary _cache = new Dictionary(); + + public long? CheckRequestType(PerformanceCapture performanceCapture) + { + var requestType = performanceCapture.RequestType; + return _cache.ContainsKey(requestType) ? _cache[requestType].GetCacheValue() : null; + } + + public void UpdateTimeoutCache(PerformanceCapture performanceCapture, long timeOutMs) + { + var requestType = performanceCapture.RequestType; + RequestCache requestCache; + if (_cache.ContainsKey(requestType)) + { + requestCache = _cache[requestType]; + requestCache.UpdateTimeoutCache(timeOutMs); + } + else + { + + requestCache = new RequestCache(timeOutMs); + _cache.Add(requestType, requestCache); + } + } + } + private class ControllerCache + { + private readonly Dictionary _cache = new Dictionary(); + + public long? GetTimeoutFromCache(PerformanceCapture performanceCapture) + { + var actionName = performanceCapture.ActionName.ToString(); + return _cache.ContainsKey(actionName) ? _cache[actionName].CheckRequestType(performanceCapture) : null; + } + + public void UpdateTimeoutCache(PerformanceCapture performanceCapture, long timeOutMs) + { + var actionName = performanceCapture.ActionName.ToString(); + ActionCache actionCache; + if (_cache.ContainsKey(actionName)) + { + actionCache = _cache[actionName]; + } + else + { + + actionCache = new ActionCache(); + _cache.Add(actionName, actionCache); + } + + actionCache.UpdateTimeoutCache(performanceCapture, timeOutMs); + } + } + + private readonly Dictionary _cache = new Dictionary(); + + public long? GetTimeoutFromCache(PerformanceCapture performanceCapture) + { + var controllerName = performanceCapture.ControllerName.ToString(); + return _cache.ContainsKey(controllerName) ? _cache[controllerName].GetTimeoutFromCache(performanceCapture) : null; + } + + public void UpdateTimeoutCache(PerformanceCapture performanceCapture, long timeOutMs) + { + var controllerName = performanceCapture.ControllerName.ToString(); + ControllerCache controllerCache; + if (_cache.ContainsKey(controllerName)) + { + controllerCache = _cache[controllerName]; + } + else + { + + controllerCache = new ControllerCache(); + _cache.Add(controllerName, controllerCache); + } + + controllerCache.UpdateTimeoutCache(performanceCapture, timeOutMs); + } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/PerformanceReportProcessor.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/PerformanceReportProcessor.cs new file mode 100644 index 0000000..c9e4737 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/PerformanceReportProcessor.cs @@ -0,0 +1,166 @@ +using e_suite.Service.Performance.Interfaces; +using e_suite.Service.Performance.Repository; +using Newtonsoft.Json; + +namespace e_suite.Service.Performance.Implementations; + +public class PerformanceReportProcessor : IPerformanceReportProcessor +{ + private const long MAX_PARAM_LENGTH = 16384; //16KB + + private readonly IPerformanceRepository _performanceRepository; + + public PerformanceReportProcessor(IPerformanceRepository performanceRepository) + { + _performanceRepository = performanceRepository; + } + + public async Task ProcessReportAsync(PerformanceCapture performanceCapture) + { + await ProcessPeformanceReportAsync(performanceCapture); + } + + public static Dictionary PrepareParameters(PerformanceCapture performanceCapture) + { + var actionParameters = new Dictionary(); + if (performanceCapture.ActionParameters != null) + { + foreach (var parameter in performanceCapture.ActionParameters) + { + var value = ""; + if (parameter.Value != null) + { + var type = parameter.Value.GetType(); + value = parameter.Value.ToString(); + if (value == type.FullName) + { + try + { + var settings = new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }; + value = JsonConvert.SerializeObject(parameter.Value, settings); + } + catch (Exception) + { + value = ""; + } + } + + if (value!.Length > MAX_PARAM_LENGTH) + { + value = ""; + } + } + + actionParameters.Add(parameter.Key, value); + } + } + + return actionParameters; + } + + public static PerformanceReportTimer ProcessPerformanceMarkers(PerformanceMarker rootMarker) + { + var result = new PerformanceReportTimer + { + Name = rootMarker.Name, + TimePoint = rootMarker.Markers[0].ElapsedNanoSeconds + }; + + var lapStart = result.TimePoint; + + var markerIndex = 0; + var childIndex = 0; + PerformanceReportTimer performanceReportTimer; + while (markerIndex < rootMarker.Markers.Count || childIndex < rootMarker.Count) + { + Marker? marker = null; + if (markerIndex < rootMarker.Markers.Count) + marker = rootMarker.Markers[markerIndex]; + + PerformanceMarker childPerformanceMarker = null!; + if (childIndex < rootMarker.Count) + childPerformanceMarker = rootMarker[childIndex]; + + if (MarkerBeforeChild(marker!, childPerformanceMarker)) + { + performanceReportTimer = new PerformanceReportTimer + { + Name = marker!.Name, + TimePoint = marker.ElapsedNanoSeconds, + TotalTimeNS = marker.ElapsedNanoSeconds - lapStart + }; + markerIndex++; + } + else + { + performanceReportTimer = ProcessPerformanceMarkers(childPerformanceMarker); + childIndex++; + } + result.Timings.Add(performanceReportTimer); + + lapStart = performanceReportTimer.TimePoint; + } + + result.TotalTimeNS = rootMarker.Markers[^1].ElapsedNanoSeconds - result.TimePoint; + return result; + } + private static bool MarkerBeforeChild(Marker marker, PerformanceMarker childPerformanceMarker) + { + if (marker == null) + return false; + + if (childPerformanceMarker == null) + return true; + + return marker.ElapsedNanoSeconds < childPerformanceMarker.Markers[0].ElapsedNanoSeconds; + } + + private static void Retry(int attempts, Action action) + { + var attempt = 0; + while (attempt < attempts) + { + try + { + action(); + break; + } + catch (Exception) + { + attempt++; + if (attempt >= attempts) + throw; + } + } + } + private static PerformanceReport PreparePerformanceReport(PerformanceCapture performanceCapture) + { + var report = new PerformanceReport( + performanceCapture.Host, + controllerName: performanceCapture.ControllerName.ToString(), + actionName: performanceCapture.ActionName.ToString(), + requestType: performanceCapture.RequestType.ToUpperInvariant(), + actionParameters: PrepareParameters(performanceCapture), + startDateTime: performanceCapture.StartDateTime, + timings: ProcessPerformanceMarkers(performanceCapture.Markers)); + + return report; + } + + private async Task SaveSlowPerformanceMetricAsync(PerformanceCapture performanceCapture) + { + var threshold = await _performanceRepository.GetSlowPerformanceThresholdMsAsync(performanceCapture); + return performanceCapture.Stopwatch.Elapsed.TotalMilliseconds > threshold; + } + private async Task ProcessPeformanceReportAsync(PerformanceCapture performanceCapture) + { + if (await SaveSlowPerformanceMetricAsync(performanceCapture)) + { + var performanceReport = PreparePerformanceReport(performanceCapture); + Retry(5, () => { _performanceRepository.SaveReportAsync(performanceReport); }); + } + } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/Stopwatch.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/Stopwatch.cs new file mode 100644 index 0000000..46feca9 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Implementations/Stopwatch.cs @@ -0,0 +1,21 @@ +using e_suite.Service.Performance.Interfaces; + +namespace e_suite.Service.Performance.Implementations; + +public class Stopwatch : IStopwatch +{ + public static Stopwatch StartNew() + { + return new Stopwatch(System.Diagnostics.Stopwatch.StartNew()); + } + + private System.Diagnostics.Stopwatch _stopwatch; + + public Stopwatch(System.Diagnostics.Stopwatch stopwatch) + { + _stopwatch = stopwatch; + } + + public TimeSpan Elapsed => _stopwatch.Elapsed; + public void Stop() => _stopwatch.Stop(); +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IPerformanceCache.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IPerformanceCache.cs new file mode 100644 index 0000000..dadb67d --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IPerformanceCache.cs @@ -0,0 +1,7 @@ +namespace e_suite.Service.Performance.Interfaces; + +public interface IPerformanceCache +{ + long? GetTimeoutFromCache(PerformanceCapture performanceCapture); + void UpdateTimeoutCache(PerformanceCapture performanceCapture, long result); +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IPerformanceReportProcessor.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IPerformanceReportProcessor.cs new file mode 100644 index 0000000..b84056a --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IPerformanceReportProcessor.cs @@ -0,0 +1,6 @@ +namespace e_suite.Service.Performance.Interfaces; + +public interface IPerformanceReportProcessor +{ + Task ProcessReportAsync(PerformanceCapture performanceReport); +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IStopwatch.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IStopwatch.cs new file mode 100644 index 0000000..a9bc195 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Interfaces/IStopwatch.cs @@ -0,0 +1,7 @@ +namespace e_suite.Service.Performance.Interfaces; + +public interface IStopwatch +{ + TimeSpan Elapsed { get; } + void Stop(); +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/IocRegistration.cs b/e-suite.Service.Performance/e-suite.Service.Performance/IocRegistration.cs new file mode 100644 index 0000000..2681242 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/IocRegistration.cs @@ -0,0 +1,21 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.Service.Performance.Implementations; +using e_suite.Service.Performance.Interfaces; +using e_suite.Service.Performance.Repository; +using Microsoft.Extensions.Caching.Memory; + +namespace e_suite.Service.Performance; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Marker.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Marker.cs new file mode 100644 index 0000000..24ecb86 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Marker.cs @@ -0,0 +1,13 @@ +namespace e_suite.Service.Performance; + +public class Marker +{ + public Marker(string name, long elapsedNanoSeconds) + { + Name = name; + ElapsedNanoSeconds = elapsedNanoSeconds; + } + + public string Name { get; set; } + public long ElapsedNanoSeconds { get; set; } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceCapture.cs b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceCapture.cs new file mode 100644 index 0000000..02a9a7b --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceCapture.cs @@ -0,0 +1,32 @@ +using e_suite.Service.Performance.Implementations; +using eSuite.Core.Clock; + +namespace e_suite.Service.Performance; + +public class PerformanceCapture +{ + private readonly IClock _clock; + public PerformanceCapture(IClock clock) : this("Round Trip", clock) + { + } + + public PerformanceCapture(string rootMarker, IClock clock) + { + _clock = clock; + Stopwatch = Stopwatch.StartNew(); + Markers = new PerformanceMarker(rootMarker, Stopwatch); + StartDateTime = _clock!.GetNow; + } + + public Stopwatch Stopwatch { get; } + + public string Host { get; set; } = null!; + public string ControllerName { get; set; } = null!; + public string ActionName { get; set; } = null!; + public string RequestType { get; set; } = null!; + + public IDictionary? ActionParameters { get; set; } = null; + + public PerformanceMarker Markers { get; } = null!; + public DateTimeOffset StartDateTime { get; } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceMaintenance.cs b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceMaintenance.cs new file mode 100644 index 0000000..30821ca --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceMaintenance.cs @@ -0,0 +1,33 @@ +using e_suite.API.Common; +using e_suite.Service.Performance.Repository; +using eSuite.Core.Clock; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Performance; + +public class PerformanceMaintenance : IPerformanceMaintenance +{ + private readonly IClock _clock; + private readonly IConfiguration _configuration; + private readonly IPerformanceRepository _performanceRepository; + + public PerformanceMaintenance(IPerformanceRepository performanceRepository, IConfiguration configuration, IClock clock) + { + _performanceRepository = performanceRepository; + _configuration = configuration; + _clock = clock; + } + + protected int GetLoginAttemptConstraints() + { + return _configuration.GetValue("Performance:DaysToKeep"); + } + + public async Task ClearOldPerformanceData() + { + var daysToKeep = GetLoginAttemptConstraints(); + + var cutoffTime = _clock.GetNow.AddDays(-daysToKeep); + await _performanceRepository.DeleteLogsBefore(cutoffTime); + } +} \ No newline at end of file diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceMarker.cs b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceMarker.cs new file mode 100644 index 0000000..82cd64d --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceMarker.cs @@ -0,0 +1,39 @@ +using e_suite.Service.Performance.Interfaces; + +namespace e_suite.Service.Performance; + +public class PerformanceMarker +{ + private List _children = new List(); + private IStopwatch _stopwatch; + + public PerformanceMarker(string name, IStopwatch stopwatch) + { + Name = name; + _stopwatch = stopwatch; + AddMarker("Start"); + } + + public string Name { get; } + + public List Markers { get; } = new List(); + + public PerformanceMarker this[string name] => _children.Single(child => child.Name.Equals(name)); + + public PerformanceMarker this[int index] => _children[index]; + + public int Count => _children.Count; + + public PerformanceMarker AddChild(string name) + { + var child = new PerformanceMarker(name, _stopwatch); + _children.Add(child); + return child; + } + + public void AddMarker(string name) + { + Markers.Add(new Marker(name, (long)(_stopwatch.Elapsed.TotalMilliseconds * 1000000))); + + } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceReport.cs b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceReport.cs new file mode 100644 index 0000000..cda6391 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceReport.cs @@ -0,0 +1,38 @@ +namespace e_suite.Service.Performance; + +public class PerformanceReport +{ + + + public PerformanceReport( + string dNSHost, + string controllerName, + string actionName, + string requestType, + IReadOnlyDictionary actionParameters, + DateTimeOffset startDateTime, + PerformanceReportTimer timings) + { + + Host = dNSHost; + ControllerName = controllerName; + ActionName = actionName; + RequestType = requestType; + ActionParameters = actionParameters; + StartDateTime = startDateTime; + Timings = timings; + } + public string Host { get; set; } + + public string ControllerName { get; set; } + + public string ActionName { get; set; } + + public string RequestType { get; set; } + + public IReadOnlyDictionary ActionParameters { get; set; } + + public DateTimeOffset StartDateTime { get; set; } + + public PerformanceReportTimer Timings { get; set; } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceReportTimer.cs b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceReportTimer.cs new file mode 100644 index 0000000..a71f3b2 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/PerformanceReportTimer.cs @@ -0,0 +1,11 @@ +namespace e_suite.Service.Performance; + +public class PerformanceReportTimer +{ + public string Name { get; set; } = null!; + public long TimePoint { get; set; } + public long TotalTimeNS { get; set; } + public double TotalTimeMS => (double)TotalTimeNS / 1000000; + + public List Timings { get; } = new List(); +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Repository/IPerformanceRepository.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Repository/IPerformanceRepository.cs new file mode 100644 index 0000000..cec70a1 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Repository/IPerformanceRepository.cs @@ -0,0 +1,9 @@ +namespace e_suite.Service.Performance.Repository; + +public interface IPerformanceRepository +{ + Task SaveReportAsync(PerformanceReport performanceReport); + + Task GetSlowPerformanceThresholdMsAsync(PerformanceCapture performanceReport); + Task DeleteLogsBefore(DateTimeOffset cutoffTime); +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/Repository/PerformanceRepository.cs b/e-suite.Service.Performance/e-suite.Service.Performance/Repository/PerformanceRepository.cs new file mode 100644 index 0000000..4f7b779 --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/Repository/PerformanceRepository.cs @@ -0,0 +1,65 @@ +using e_suite.Database.Core; +using e_suite.Service.Performance.Interfaces; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; + +namespace e_suite.Service.Performance.Repository; + +public class PerformanceRepository : IPerformanceRepository +{ + private readonly IEsuiteDatabaseDbContext _esuiteDatabaseDbContext; + private readonly IPerformanceCache _performanceCache; + + public PerformanceRepository(IEsuiteDatabaseDbContext esuiteDatabaseDbContext, IPerformanceCache performanceCache) + { + + _esuiteDatabaseDbContext = esuiteDatabaseDbContext; + _performanceCache = performanceCache; + } + + public async Task GetSlowPerformanceThresholdMsAsync(PerformanceCapture performanceReport) + { + var cacheResult = _performanceCache.GetTimeoutFromCache(performanceReport); + if (cacheResult.HasValue) + { + return cacheResult.Value; + } + var totalTimeMSObj = await _esuiteDatabaseDbContext.PerformanceThresholds + .Where(p => p.ControllerName == performanceReport.ControllerName && + p.ActionName == performanceReport.ActionName && + p.RequestType == performanceReport.RequestType).Select(r => new { r.TotalTimeMS }) + .Union(_esuiteDatabaseDbContext.PerformanceThresholds + .Where(p => p.ControllerName == string.Empty && + p.ControllerName == string.Empty && + p.RequestType == string.Empty) + .Select(r => new { r.TotalTimeMS })).FirstOrDefaultAsync(); + var res = (long)totalTimeMSObj!.TotalTimeMS; + _performanceCache.UpdateTimeoutCache(performanceReport, res); + return res; + } + + public async Task DeleteLogsBefore(DateTimeOffset cutoffTime) + { + var oldRows = _esuiteDatabaseDbContext.PerformanceReports.Where(x => x.StartDateTime < cutoffTime); + _esuiteDatabaseDbContext.PerformanceReports.RemoveRange(oldRows); + + await _esuiteDatabaseDbContext.NoAuditSaveChangesAsync(); + } + + public async Task SaveReportAsync(PerformanceReport performanceReport) + { + await _esuiteDatabaseDbContext.PerformanceReports.AddAsync(new Database.Core.Tables.Diagnostics.PerformanceReport() + { + Host = performanceReport.Host, + ActionName = performanceReport.ActionName, + ControllerName = performanceReport.ControllerName, + RequestType = performanceReport.RequestType, + ActionParameters = JsonConvert.SerializeObject(performanceReport.ActionParameters), + StartDateTime = performanceReport.StartDateTime, + Timings = JsonConvert.SerializeObject(performanceReport.Timings.Timings), + TotalTimeMS = (int)performanceReport.Timings.TotalTimeMS + }); + + await _esuiteDatabaseDbContext.NoAuditSaveChangesAsync(); + } +} diff --git a/e-suite.Service.Performance/e-suite.Service.Performance/e-suite.Service.Performance.csproj b/e-suite.Service.Performance/e-suite.Service.Performance/e-suite.Service.Performance.csproj new file mode 100644 index 0000000..14fb40b --- /dev/null +++ b/e-suite.Service.Performance/e-suite.Service.Performance/e-suite.Service.Performance.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + e_suite.Service.Performance + enable + enable + + + + + + + + + + + + + diff --git a/e-suite.Service.Performance/nuget.config b/e-suite.Service.Performance/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Service.Performance/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.Sentinel/.gitattributes b/e-suite.Service.Sentinel/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Service.Sentinel/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Service.Sentinel/.gitignore b/e-suite.Service.Sentinel/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Service.Sentinel/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Service.Sentinel/.runsettings b/e-suite.Service.Sentinel/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Service.Sentinel/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.Sentinel/README.md b/e-suite.Service.Sentinel/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Service.Sentinel/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/Helpers/FakeController.cs b/e-suite.Service.Sentinel/Sentinel.UnitTests/Helpers/FakeController.cs new file mode 100644 index 0000000..68ac5c4 --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/Helpers/FakeController.cs @@ -0,0 +1,31 @@ +using System.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Routing; + +namespace Sentinel.UnitTests.Helpers; + +public class FakeController : ControllerBase +{ + public static FakeController CreateFakeController() + { + byte[] ipAddress = { 143, 24, 20, 36 }; + return CreateFakeController(ipAddress); + } + + public static FakeController CreateFakeController(byte[] ipAddress) + { + var fakeController = new FakeController(); + + HttpContext fakeHttpContext = new DefaultHttpContext(); + + fakeHttpContext.Connection.RemoteIpAddress = new IPAddress(ipAddress); + var routeData = new RouteData(); + var controllerActionDescriptor = new ControllerActionDescriptor(); + var fakeActionContext = new ActionContext(fakeHttpContext, routeData, controllerActionDescriptor); + fakeController.ControllerContext = new ControllerContext(fakeActionContext); + + return fakeController; + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/Helpers/SentinelTestBase.cs b/e-suite.Service.Sentinel/Sentinel.UnitTests/Helpers/SentinelTestBase.cs new file mode 100644 index 0000000..15f53a5 --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/Helpers/SentinelTestBase.cs @@ -0,0 +1,23 @@ +using e_suite.Service.Sentinel; +using e_suite.UnitTestCore; +using Sentinel.UnitTests.Repository; + +namespace Sentinel.UnitTests.Helpers; + +public class SentinelTestBase : TestBase +{ + public FakeSentinelRepository SentinelRepository = null!; + + public ISentinel Sentinel = null!; + public ISentinelMaintenance SentinelMaintenance = null!; + + public override async Task Setup() + { + await base.Setup(); + + SentinelRepository = new FakeSentinelRepository(); + + Sentinel = new e_suite.Service.Sentinel.Sentinel(_fakeClock, _configuration, SentinelRepository); + SentinelMaintenance = new e_suite.Service.Sentinel.SentinelMaintenance(_fakeClock, _configuration, SentinelRepository); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/Repository/FakeSentinelRepository.cs b/e-suite.Service.Sentinel/Sentinel.UnitTests/Repository/FakeSentinelRepository.cs new file mode 100644 index 0000000..fa1a28e --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/Repository/FakeSentinelRepository.cs @@ -0,0 +1,39 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.UnitTestCore; + +namespace Sentinel.UnitTests.Repository +{ + public class FakeSentinelRepository : FakeRepository, ISentinelRepository + { + public int AccessAttempts = 0; + public string IpAddress = string.Empty; + public DateTimeOffset EarliestAttemptTime = DateTimeOffset.MinValue; + public List FailedAccessAttempts = new(); + + public Task AddFailedAccessAttempt(FailedAccessAttempt failedLoginAttempt, CancellationToken cancellationToken) + { + FailedAccessAttempts.Add(failedLoginAttempt); + + return Task.CompletedTask; + } + + public Task GetAccessAttemptsSince(string ipAddress, DateTimeOffset earliestAttemptTime, CancellationToken cancellationToken) + { + IpAddress = ipAddress; + EarliestAttemptTime = earliestAttemptTime; + + return Task.FromResult(AccessAttempts); + } + + public Task DeleteAccessAttemptsBefore(DateTimeOffset earliestAttemptTime) + { + var itemsToRemove = FailedAccessAttempts.Where(x => x.AttemptedTime < earliestAttemptTime).ToList(); + foreach (var item in itemsToRemove) + { + FailedAccessAttempts.Remove(item); + } + return Task.CompletedTask; + } + } +} diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel.UnitTests.csproj b/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel.UnitTests.csproj new file mode 100644 index 0000000..c10fc0a --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel.UnitTests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel/CheckSecurityUnitTests.cs b/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel/CheckSecurityUnitTests.cs new file mode 100644 index 0000000..1929f36 --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel/CheckSecurityUnitTests.cs @@ -0,0 +1,108 @@ +using System.Diagnostics; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Primitives; +using NUnit.Framework; +using Sentinel.UnitTests.Helpers; + +namespace Sentinel.UnitTests.Sentinel +{ + [TestFixture] + public class CheckSecurityUnitTests : SentinelTestBase + { + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(5)] + public async Task CheckSecurity_BelowMaxAttempts_ReturnsNull(int accessAttempts) + { + //Arrange + SentinelRepository.AccessAttempts = accessAttempts; + + var fakeController = FakeController.CreateFakeController(); + + //Act + var result = await Sentinel.CheckSecurity(fakeController, default); + + //Assert + Assert.That(result, Is.Null); + } + + [Test] + public async Task CheckSecurity_AboveMaxAttempts_ReturnsUnauthorized() + { + //Arragne + SentinelRepository.AccessAttempts = 6; + + _fakeClock.DateTime = new DateTimeOffset(2022, 9, 23, 12, 06, 45, TimeSpan.Zero); + var expectedEarliestAttemptTime = new DateTimeOffset(2022, 9, 23, 11, 06, 45, TimeSpan.Zero); + + FakeController fakeController = FakeController.CreateFakeController(); + + //Act + var result = await Sentinel.CheckSecurity(fakeController, default); + + //Assert + Assert.That(SentinelRepository.IpAddress, Is.EqualTo("143.24.20.36")); + Assert.That(SentinelRepository.EarliestAttemptTime, Is.EqualTo(expectedEarliestAttemptTime)); + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.TypeOf()); + } + + [Test] + public async Task CheckSecurityBehindReverseProxy_AboveMaxAttempts_ReturnsUnauthorized() + { + //Arragne + SentinelRepository.AccessAttempts = 6; + + _fakeClock.DateTime = new DateTimeOffset(2022, 9, 23, 12, 06, 45, TimeSpan.Zero); + var expectedEarliestAttemptTime = new DateTimeOffset(2022, 9, 23, 11, 06, 45, TimeSpan.Zero); + + var fakeController = FakeController.CreateFakeController(); + fakeController.Request.Headers["X-Forwarded-For"] = "80.1.1.50"; + + //Act + var result = await Sentinel.CheckSecurity(fakeController, default); + + //Assert + //Assert.That(SentinelRepository.IpAddress, Is.EqualTo("143.24.20.36")); + Assert.That(SentinelRepository.IpAddress, Is.EqualTo("80.1.1.50")); + Assert.That(SentinelRepository.EarliestAttemptTime, Is.EqualTo(expectedEarliestAttemptTime)); + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.TypeOf()); + } + + [Test] + public async Task CheckSecurityBehindReverseProxy_BehindReverseProxy_RemovedPortFromIpAddress() + { + //Arragne + SentinelRepository.AccessAttempts = 6; + + _fakeClock.DateTime = new DateTimeOffset(2022, 9, 23, 12, 06, 45, TimeSpan.Zero); + var expectedEarliestAttemptTime = new DateTimeOffset(2022, 9, 23, 11, 06, 45, TimeSpan.Zero); + + var fakeController = FakeController.CreateFakeController(); + fakeController.Request.Headers["X-Forwarded-For"] = "80.1.1.50:8472"; + + //Act + var result = await Sentinel.CheckSecurity(fakeController, default); + + //Assert + //Assert.That(SentinelRepository.IpAddress, Is.EqualTo("143.24.20.36")); + Assert.That(SentinelRepository.IpAddress, Is.EqualTo("80.1.1.50")); + Assert.That(SentinelRepository.EarliestAttemptTime, Is.EqualTo(expectedEarliestAttemptTime)); + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.TypeOf()); + } + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel/LogBadRequestUnitTests.cs b/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel/LogBadRequestUnitTests.cs new file mode 100644 index 0000000..26e808f --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/Sentinel/LogBadRequestUnitTests.cs @@ -0,0 +1,30 @@ +using NUnit.Framework; +using Sentinel.UnitTests.Helpers; + +namespace Sentinel.UnitTests.Sentinel; + +[TestFixture] +public class LogBadRequestUnitTests : SentinelTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task LogBadRequest_WhenCalled_PassesCorrectInformationToRepository() + { + //Arrange + FakeController fakeController = FakeController.CreateFakeController(); + + //Act + await Sentinel.LogBadRequest(fakeController, default); + + //Assert + Assert.That(SentinelRepository.FailedAccessAttempts.Count, Is.EqualTo(1)); + + Assert.That(SentinelRepository.FailedAccessAttempts[0].IPAddress, Is.EqualTo("143.24.20.36")); + Assert.That(SentinelRepository.FailedAccessAttempts[0].AttemptedTime, Is.EqualTo(_fakeClock.GetNow)); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/Sentinel.UnitTests/SentinelMaintenance/ClearOldSentinelDataUnitTests.cs b/e-suite.Service.Sentinel/Sentinel.UnitTests/SentinelMaintenance/ClearOldSentinelDataUnitTests.cs new file mode 100644 index 0000000..470e85f --- /dev/null +++ b/e-suite.Service.Sentinel/Sentinel.UnitTests/SentinelMaintenance/ClearOldSentinelDataUnitTests.cs @@ -0,0 +1,53 @@ +using e_suite.Database.Core.Tables.Sentinel; +using NUnit.Framework; +using Sentinel.UnitTests.Helpers; + +namespace Sentinel.UnitTests.SentinelMaintenance; + +[TestFixture] +public class ClearOldSentinelDataUnitTests : SentinelTestBase +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public void ClearOldSentinelData_WhenCalled_DeletesOldData() + { + //Arrange + _fakeClock.DateTime = new DateTimeOffset(2022, 9, 23, 12, 06, 45, TimeSpan.Zero); + + SentinelRepository.FailedAccessAttempts.Add( new FailedAccessAttempt + { + AttemptedTime = _fakeClock.DateTime.AddMinutes(-120), + IPAddress = "127.0.0.1" + }); + + //Act + SentinelMaintenance.ClearOldSentinelData(); + + //Assert + Assert.That(SentinelRepository.FailedAccessAttempts.Count, Is.EqualTo(0)); + } + + [Test] + public void ClearOldSentinelData_WhenCalled_DoesNotAlterCurrentData() + { + //Arrange + _fakeClock.DateTime = new DateTimeOffset(2022, 9, 23, 12, 06, 45, TimeSpan.Zero); + + SentinelRepository.FailedAccessAttempts.Add(new FailedAccessAttempt + { + AttemptedTime = _fakeClock.DateTime.AddMinutes(-15), + IPAddress = "127.0.0.1" + }); + + //Act + SentinelMaintenance.ClearOldSentinelData(); + + //Assert + Assert.That(SentinelRepository.FailedAccessAttempts.Count, Is.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/azure-pipelines.yml b/e-suite.Service.Sentinel/azure-pipelines.yml new file mode 100644 index 0000000..03bdd95 --- /dev/null +++ b/e-suite.Service.Sentinel/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Service.Sentinel/e-suite.Service.Sentinel.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/SentinelTests.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/SentinelTests.cs new file mode 100644 index 0000000..4400fab --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/SentinelTests.cs @@ -0,0 +1,122 @@ +using e_suite.Database.Core.Tables.Sentinel; +using e_suite.UnitTestCore; +using eSuite.Core.Clock; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Sentinel.Tests; + +public class SentinelTests : TestBase +{ + private Mock _sentinelRepository; + private Mock _controllerBaseMock; + private IClock _clock; + private Sentinel _sentinel; + private HttpContext _httpContext; + + [SetUp] + public void SetUp() + { + _sentinelRepository = new Mock(); + _sentinelRepository.Setup>(x => x.GetAccessAttemptsSince(It.IsAny(), It.IsAny())).ReturnsAsync(100); + _controllerBaseMock = new Mock(); + _httpContext = new DefaultHttpContext(); + _httpContext.Request.Path = "/Test/3133/TestController/TestAction"; + _httpContext.Connection.RemoteIpAddress = new System.Net.IPAddress(0x1234567); + var controllerContext = new ControllerContext() + { + HttpContext = _httpContext + }; + _controllerBaseMock.Object.ControllerContext = controllerContext; + _clock = new UtcClock(); + _controllerBaseMock.Setup(x => x.Unauthorized(It.IsAny())).Returns(new UnauthorizedObjectResult(new ProblemDetails() + { + Title = "Access Denied", + Detail = "Too many access attempts" + + })); + _sentinel = new Sentinel(_clock, base._configuration, _sentinelRepository.Object); + } + + [Test] + public void LogBadRequest_NullController_ThrowsException() + { + Assert.ThrowsAsync(() => _sentinel.LogBadRequest(null!)); + } + + [Test] + public void LogBadRequest_NormalConditian_HitsSaveRepoMethod() + { + _controllerBaseMock.SetupAllProperties(); + + _sentinel.LogBadRequest(_controllerBaseMock.Object).GetAwaiter().GetResult(); + + _sentinelRepository.Verify(r => r.AddFailedAccessAttempt(It.IsAny())); + } + + [Test] + public void CheckSecurity_NullController_ThrowsException() + { + Assert.ThrowsAsync(() => _sentinel.CheckSecurity(null!)); + } + + [Test] + public void CheckSecurity_BlockedUsersVlues_Unauthorized() + { + AddAtemptConditoins(); + _sentinelRepository.Setup(x => x.GetAccessAttemptsSince(_httpContext.Connection.RemoteIpAddress.ToString(), It.IsAny())).ReturnsAsync(() => 200); + _sentinel = new Sentinel(_clock,base._configuration, _sentinelRepository.Object); + + var res = _sentinel.CheckSecurity(_controllerBaseMock.Object).GetAwaiter().GetResult(); + + Assert.That(res, Is.Not.Null); + Assert.That(res, Is.TypeOf()); + } + + [Test] + public void CheckSecurity_NormalUserConditions_returnsNull() + { + AddAtemptConditoins(); + _sentinelRepository.Setup(x => x.GetAccessAttemptsSince(_httpContext.Connection.RemoteIpAddress.ToString(), It.IsAny())).ReturnsAsync(() => 1); + _sentinel = new Sentinel(_clock, base._configuration, _sentinelRepository.Object); + + var res = _sentinel.CheckSecurity(_controllerBaseMock.Object).GetAwaiter().GetResult(); + + Assert.That(res, Is.Null); + + } + + [Test] + public void CheckSecurity_RepoReturnsMinusValue_returnsNull() + { + AddAtemptConditoins(); + _sentinelRepository.Setup(x => x.GetAccessAttemptsSince(_httpContext.Connection.RemoteIpAddress.ToString(), It.IsAny())).ReturnsAsync(() => -51); + _sentinel = new Sentinel(_clock, base._configuration, _sentinelRepository.Object); + + var res = _sentinel.CheckSecurity(_controllerBaseMock.Object).GetAwaiter().GetResult(); + + Assert.That(res, Is.Null); + } + [Test] + public void CheckSecurity_ConfigurationsValuesDontExist_ReturnsNUll() + { + + _sentinelRepository.Setup(x => x.GetAccessAttemptsSince(_httpContext.Connection.RemoteIpAddress.ToString(), It.IsAny())).ReturnsAsync(() => -51); + _sentinel = new Sentinel(_clock, base._configuration, _sentinelRepository.Object); + var res = _sentinel.CheckSecurity(_controllerBaseMock.Object).GetAwaiter().GetResult(); + Assert.That(res,Is.Null); + + } + + private void AddAtemptConditoins() + { + var configurationBuilderSetings = new Dictionary() + { + {"Sentinel:LoginAttemptTimeoutMinutes","10" }, + {"Sentinel:MaxLoginAttempts","12" } + }; + base._configuration = new ConfigurationBuilder().AddInMemoryCollection(configurationBuilderSetings).Build(); + + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/Usings.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/Usings.cs new file mode 100644 index 0000000..5ed9a6c --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/Usings.cs @@ -0,0 +1,2 @@ +global using NUnit.Framework; +global using Moq; \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/e-suite.Service.Sentinel.Tests.csproj b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/e-suite.Service.Sentinel.Tests.csproj new file mode 100644 index 0000000..b3b2936 --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.Tests/e-suite.Service.Sentinel.Tests.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + e_suite.Service.Sentinel.Tests + enable + enable + + false + + + + + + + + + + + + + + + + + diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel.sln b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.sln new file mode 100644 index 0000000..53e7d4e --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.Sentinel", "e-suite.Service.Sentinel\e-suite.Service.Sentinel.csproj", "{39F26B11-2367-4A9B-80DB-FE9FA1CA3924}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{52B7BAAF-29C0-4AF6-AF28-6E62D6CE3093}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{380C726D-4CB8-409D-A88E-A70B506DB111}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sentinel.UnitTests", "Sentinel.UnitTests\Sentinel.UnitTests.csproj", "{48CAF4FD-CA41-4085-8F0E-3D6E61F49394}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39F26B11-2367-4A9B-80DB-FE9FA1CA3924}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39F26B11-2367-4A9B-80DB-FE9FA1CA3924}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39F26B11-2367-4A9B-80DB-FE9FA1CA3924}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39F26B11-2367-4A9B-80DB-FE9FA1CA3924}.Release|Any CPU.Build.0 = Release|Any CPU + {48CAF4FD-CA41-4085-8F0E-3D6E61F49394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48CAF4FD-CA41-4085-8F0E-3D6E61F49394}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48CAF4FD-CA41-4085-8F0E-3D6E61F49394}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48CAF4FD-CA41-4085-8F0E-3D6E61F49394}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {380C726D-4CB8-409D-A88E-A70B506DB111} = {52B7BAAF-29C0-4AF6-AF28-6E62D6CE3093} + {48CAF4FD-CA41-4085-8F0E-3D6E61F49394} = {380C726D-4CB8-409D-A88E-A70B506DB111} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {80958471-9F26-4857-A0CE-9786820620BF} + EndGlobalSection +EndGlobal diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/GlobalSuppressions.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/ISentinel.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/ISentinel.cs new file mode 100644 index 0000000..0be3a37 --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/ISentinel.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Mvc; + +namespace e_suite.Service.Sentinel; + +public interface ISentinel +{ + Task CheckSecurity(ControllerBase controller, CancellationToken cancellationToken); + Task LogBadRequest(ControllerBase controller, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/ISentinelMaintenance.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/ISentinelMaintenance.cs new file mode 100644 index 0000000..e04b596 --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/ISentinelMaintenance.cs @@ -0,0 +1,6 @@ +namespace e_suite.Service.Sentinel; + +public interface ISentinelMaintenance +{ + Task ClearOldSentinelData(); +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/IocRegistration.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/IocRegistration.cs new file mode 100644 index 0000000..1b6eddb --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/IocRegistration.cs @@ -0,0 +1,15 @@ +using Autofac; +using e_suite.API.Common.repository; +using e_suite.Service.Sentinel.Repository; + +namespace e_suite.Service.Sentinel; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/Repository/SentinelRepository.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/Repository/SentinelRepository.cs new file mode 100644 index 0000000..66182fc --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/Repository/SentinelRepository.cs @@ -0,0 +1,35 @@ +using e_suite.API.Common.repository; +using e_suite.Database.Core; +using e_suite.Database.Core.Tables.Sentinel; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Service.Sentinel.Repository; + +public class SentinelRepository : ISentinelRepository +{ + private readonly IEsuiteDatabaseDbContext _esuiteDatabaseDbContext; + + public SentinelRepository(IEsuiteDatabaseDbContext esuiteDatabaseDbContext) + { + _esuiteDatabaseDbContext = esuiteDatabaseDbContext; + } + + public async Task AddFailedAccessAttempt(FailedAccessAttempt failedLoginAttempt, CancellationToken cancellationToken) + { + await _esuiteDatabaseDbContext.FailedAccessAttempts.AddAsync(failedLoginAttempt, cancellationToken); + await _esuiteDatabaseDbContext.NoAuditSaveChangesAsync(cancellationToken); + } + + public async Task GetAccessAttemptsSince(string ipAddress, DateTimeOffset earliestAttemptTime, CancellationToken cancellationToken) + { + return await _esuiteDatabaseDbContext.FailedAccessAttempts.CountAsync(x => + x.IPAddress == ipAddress && x.AttemptedTime >= earliestAttemptTime, cancellationToken); + } + + public async Task DeleteAccessAttemptsBefore(DateTimeOffset earliestAttemptTime) + { + var itemsToRemove = _esuiteDatabaseDbContext.FailedAccessAttempts.Where(x => x.AttemptedTime < earliestAttemptTime); + _esuiteDatabaseDbContext.FailedAccessAttempts.RemoveRange(itemsToRemove); + await _esuiteDatabaseDbContext.NoAuditSaveChangesAsync(); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/Sentinel.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/Sentinel.cs new file mode 100644 index 0000000..a8e123e --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/Sentinel.cs @@ -0,0 +1,70 @@ +using System.Diagnostics; +using e_suite.API.Common.repository; +using e_suite.Database.Core.Tables.Sentinel; +using eSuite.Core.Clock; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Sentinel; + +public class Sentinel : SentinelBase, ISentinel +{ + private const string AccessDenied = "Access denied"; + public Sentinel(IClock clock, IConfiguration configuration, ISentinelRepository sentinelRepository) : base(clock, configuration, sentinelRepository) + { + } + + public async Task LogBadRequest(ControllerBase controller, CancellationToken cancellationToken) + { + var failedLoginAttempt = new FailedAccessAttempt + { + IPAddress = GetIPAddress(controller), + AttemptedTime = Clock.GetNow + }; + + await SentinelRepository.AddFailedAccessAttempt(failedLoginAttempt, cancellationToken); + } + + private static string GetIPAddress(ControllerBase controller) + { + var ipAddress = controller.HttpContext.Request.Headers["X-Forwarded-For"].ToString(); + if (string.IsNullOrWhiteSpace(ipAddress)) + ipAddress = controller.HttpContext.Connection.RemoteIpAddress?.ToString(); + + if (ipAddress == null) + throw new NullReferenceException("Unable to find IP Address"); + + ipAddress = RemovePort(ipAddress); + return ipAddress; + } + + private static string RemovePort(string ipAddress) + { + var portSeparatorIndex = ipAddress.IndexOf(":"); + if (portSeparatorIndex != -1) + { + return ipAddress.Substring(0, portSeparatorIndex); + } + + return ipAddress; + } + + public async Task CheckSecurity(ControllerBase controller, CancellationToken cancellationToken) + { + var (earliestAttemptTime, maxLoginAttempts) = GetLoginAttemptConstraints(); + + var ipAddress = GetIPAddress(controller); + + var loginAttempts = await SentinelRepository.GetAccessAttemptsSince(ipAddress, earliestAttemptTime, cancellationToken); + + if (loginAttempts > maxLoginAttempts) + return controller.Unauthorized(new ProblemDetails + { + Title = AccessDenied, + Detail = "You are locked out. You can try again in 1hr or contact your admin." + } + ); + + return null; + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/SentinelBase.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/SentinelBase.cs new file mode 100644 index 0000000..c826abd --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/SentinelBase.cs @@ -0,0 +1,29 @@ +using e_suite.API.Common.repository; +using eSuite.Core.Clock; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Sentinel; + +public class SentinelBase +{ + protected readonly IConfiguration Configuration; + protected readonly IClock Clock; + protected readonly ISentinelRepository SentinelRepository; + + public SentinelBase(IClock clock, IConfiguration configuration, ISentinelRepository sentinelRepository) + { + Clock = clock; + Configuration = configuration; + SentinelRepository = sentinelRepository; + } + + protected (DateTimeOffset earliestAttemptTime, int maxLoginAttempts) GetLoginAttemptConstraints() + { + var loginAttemptTimeoutMinutes = Configuration.GetValue("Sentinel:LoginAttemptTimeoutMinutes"); + var maxLoginAttempts = Configuration.GetValue("Sentinel:MaxLoginAttempts"); + + var earliestAttemptTime = Clock.GetNow.AddMinutes(-loginAttemptTimeoutMinutes); + + return (earliestAttemptTime, maxLoginAttempts); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/SentinelMaintenance.cs b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/SentinelMaintenance.cs new file mode 100644 index 0000000..3880047 --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/SentinelMaintenance.cs @@ -0,0 +1,20 @@ +using e_suite.API.Common.repository; +using eSuite.Core.Clock; +using Microsoft.Extensions.Configuration; + +namespace e_suite.Service.Sentinel; + +public class SentinelMaintenance : SentinelBase, ISentinelMaintenance +{ + public SentinelMaintenance(IClock clock, IConfiguration configuration, ISentinelRepository sentinelRepository) : base(clock, configuration, sentinelRepository) + { + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0059:Unnecessary assignment of a value", Justification = "Leaving the variable name is clearer")] + public async Task ClearOldSentinelData() + { + var (earliestAttemptTime, maxLoginAttempts) = GetLoginAttemptConstraints(); + + await SentinelRepository.DeleteAccessAttemptsBefore(earliestAttemptTime); + } +} \ No newline at end of file diff --git a/e-suite.Service.Sentinel/e-suite.Service.Sentinel/e-suite.Service.Sentinel.csproj b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/e-suite.Service.Sentinel.csproj new file mode 100644 index 0000000..1c21020 --- /dev/null +++ b/e-suite.Service.Sentinel/e-suite.Service.Sentinel/e-suite.Service.Sentinel.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + e_suite.Service.Sentinel + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Service.Sentinel/nuget.config b/e-suite.Service.Sentinel/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Service.Sentinel/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/.gitattributes b/e-suite.Service.SigmaImporter/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Service.SigmaImporter/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/.gitignore b/e-suite.Service.SigmaImporter/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Service.SigmaImporter/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Service.SigmaImporter/.runsettings b/e-suite.Service.SigmaImporter/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Service.SigmaImporter/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/README.md b/e-suite.Service.SigmaImporter/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Service.SigmaImporter/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/GmgProfileImporter/ImportGmgProfilesUnitTestsWithMySql.cs b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/GmgProfileImporter/ImportGmgProfilesUnitTestsWithMySql.cs new file mode 100644 index 0000000..fb6fa1d --- /dev/null +++ b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/GmgProfileImporter/ImportGmgProfilesUnitTestsWithMySql.cs @@ -0,0 +1,229 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.Repository; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; +using SigmaImporter.UnitTests.Helpers; + +namespace SigmaImporter.UnitTests.GmgProfileImporter; + +[TestFixture] +public class ImportGmgProfilesUnitTestsWithMySql : GmgProfileImporterTestBaseWithMySql +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenGmgProfilesNotPresent_CreatesNewGmgProfile() + { + //Arrange + var getGmgProfileCounter = 0; + + var gmgGlossaryItem = new GlossaryItem + { + Parent = new GlossaryItem + { + Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"), + Name = "System" + }, + Name = "GMG Profile", + Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702") + }; + + GlossariesManagerMock.Setup(x => + x.GetGlossaryItem(It.IsAny(), It.IsAny(), + It.IsAny())) + .Returns( + (auditUserDetails, generalIdRef, cancellationToken) => + { + if (generalIdRef?.Guid == GmgProfileGuid) + { + getGmgProfileCounter++; + if (getGmgProfileCounter == 1) + throw new NotFoundException("Unable to find glossary"); + else + { + return Task.FromResult(gmgGlossaryItem)!; + } + + } + + throw new NotFoundException("Unable to find glossary"); + }); + + //Act + await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails); + + //Assert + GlossariesManagerMock.Verify(x => x.GetGlossaryItem(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(2)); + GlossariesManagerMock.Verify( x => x.AddGlossaryItem(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task WhenGmgProfilesIsPresent_DoesNotCreateNewItem() + { + //Arrange + var getGmgProfileCounter = 0; + + var gmgGlossaryItem = new GlossaryItem + { + Parent = new GlossaryItem + { + Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"), + Name = "System" + }, + Name = "GMG Profile", + Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702") + }; + + GlossariesManagerMock.Setup(x => + x.GetGlossaryItem(It.IsAny(), It.IsAny(), + It.IsAny())) + .Returns( + (auditUserDetails, generalIdRef, cancellationToken) => + { + if (generalIdRef?.Guid == GmgProfileGuid) + { + getGmgProfileCounter++; + if (getGmgProfileCounter == 1) + return Task.FromResult(gmgGlossaryItem)!; + + } + + throw new NotFoundException("Unable to find glossary"); + }); + + //Act + await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails); + + //Assert + GlossariesManagerMock.Verify(x => x.GetGlossaryItem(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + GlossariesManagerMock.Verify(x => x.AddGlossaryItem(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public async Task NoGMGProfilesReturned_AddGlossaryItemsCalledOnce() + { + //Arrange + var getGmgProfileCounter = 0; + + var gmgGlossaryItem = new GlossaryItem + { + Parent = new GlossaryItem + { + Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"), + Name = "System" + }, + Name = "GMG Profile", + Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702") + }; + + GlossariesManagerMock.Setup(x => + x.GetGlossaryItem(It.IsAny(), It.IsAny(), + It.IsAny())) + .Returns( + (auditUserDetails, generalIdRef, cancellationToken) => + { + if (generalIdRef?.Guid == GmgProfileGuid) + { + getGmgProfileCounter++; + if (getGmgProfileCounter == 1) + return Task.FromResult(gmgGlossaryItem)!; + + } + + throw new NotFoundException("Unable to find glossary"); + }); + + List gmgProfiles = []; + + SigmaFileBrowserRepositoryMock.Setup(x => x.GetActiveGmgProfiles()).ReturnsAsync( gmgProfiles ); + + var newGlossaryItemCount = 0; + + GlossariesManagerMock + .Setup(x => x.AddGlossaryItems(It.IsAny(), It.IsAny>(), + It.IsAny())) + .Returns, CancellationToken>( + ((auditUserDetails, newGlossaryItem, cancellationToken) => + { + newGlossaryItemCount = newGlossaryItem.Count(); + return Task.FromResult(gmgProfiles); + } ) + ); + + //Act + await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails); + + //Assert + GlossariesManagerMock.Verify(x => x.AddGlossaryItems(It.IsAny(), It.IsAny>(), It.IsAny()), Times.Once); + Assert.That(newGlossaryItemCount, Is.EqualTo(0)); + } + + [Test] + public async Task OneGMGProfilesReturned_AddGlossaryItemsCalledWithOneItem() + { + //Arrange + var getGmgProfileCounter = 0; + + var gmgGlossaryItem = new GlossaryItem + { + Parent = new GlossaryItem + { + Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E"), + Name = "System" + }, + Name = "GMG Profile", + Guid = new Guid("BBA078CF-8326-40B8-92EC-ECD9A2017702") + }; + + GlossariesManagerMock.Setup(x => + x.GetGlossaryItem(It.IsAny(), It.IsAny(), + It.IsAny())) + .Returns( + (auditUserDetails, generalIdRef, cancellationToken) => + { + if (generalIdRef?.Guid == GmgProfileGuid) + { + getGmgProfileCounter++; + if (getGmgProfileCounter == 1) + return Task.FromResult(gmgGlossaryItem)!; + + } + + throw new NotFoundException("Unable to find glossary"); + }); + + List gmgProfiles = + [ + new() { Name = "Test Profile", Number = 1 } + ]; + + SigmaFileBrowserRepositoryMock.Setup(x => x.GetActiveGmgProfiles()).ReturnsAsync(gmgProfiles); + + var newGlossaryItemCount = 0; + + GlossariesManagerMock + .Setup(x => x.AddGlossaryItems(It.IsAny(), It.IsAny>(), + It.IsAny())) + .Returns, CancellationToken>( + ((auditUserDetails, newGlossaryItem, cancellationToken) => + { + newGlossaryItemCount = newGlossaryItem.Count(); + return Task.FromResult(gmgProfiles); + }) + ); + + //Act + await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails); + + //Assert + GlossariesManagerMock.Verify(x => x.AddGlossaryItems(It.IsAny(), It.IsAny>(), It.IsAny()), Times.Once); + Assert.That(newGlossaryItemCount, Is.EqualTo(1)); + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/GmgProfileImporter/ImportGmgProfilesUnitTestsWithoutMySql.cs b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/GmgProfileImporter/ImportGmgProfilesUnitTestsWithoutMySql.cs new file mode 100644 index 0000000..d84a694 --- /dev/null +++ b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/GmgProfileImporter/ImportGmgProfilesUnitTestsWithoutMySql.cs @@ -0,0 +1,29 @@ +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; +using Moq; +using NUnit.Framework; +using SigmaImporter.UnitTests.Helpers; + +namespace SigmaImporter.UnitTests.GmgProfileImporter; + +[TestFixture] +public class ImportGmgProfilesUnitTestsWithoutMySql : GmgProfileImporterTestBaseWithoutMySql +{ + [SetUp] + public override async Task Setup() + { + await base.Setup(); + } + + [Test] + public async Task WhenDatabaseServerIsEmpty_ThenDoesNothing() + { + //Arrange + + //Act + await GmgProfileImporter.DoGmgProfileImport(AuditUserDetails); + + //Assert + GlossariesManagerMock.Verify( x => x.GetGlossaryItem(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/Helpers/GmgProfileImporterTestBaseWithMySql.cs b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/Helpers/GmgProfileImporterTestBaseWithMySql.cs new file mode 100644 index 0000000..4ec0ef3 --- /dev/null +++ b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/Helpers/GmgProfileImporterTestBaseWithMySql.cs @@ -0,0 +1,63 @@ +using e_suite.API.Common; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.GmgProfiles; +using e_suite.Service.SigmaImporter.Helpers; +using e_suite.Service.SigmaImporter.Repository; +using e_suite.UnitTestCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Moq; + +namespace SigmaImporter.UnitTests.Helpers; + +public class GmgProfileImporterTestBaseWithMySql : TestBase +{ + protected Mock SigmaFileBrowserRepositoryMock { get; set; } = null!; + protected Mock GlossariesManagerMock { get; set; } = null!; + protected Mock LoggerMock { get; set; } = null!; + + protected Guid GmgProfileGuid { get; } = new("BBA078CF-8326-40B8-92EC-ECD9A2017702"); + + protected ImportGlossaryHelper ImportGlossaryHelper { get; set; } = null!; + + protected AuditUserDetails AuditUserDetails = new() + { + Comment = "SigmaImporter Automated import", + UserDisplayName = "MessageProcessor" + }; + + public IGmgProfileImporter GmgProfileImporter { get; set; } = null!; + + public override async Task Setup() + { + await base.Setup(); + SigmaFileBrowserRepositoryMock = new Mock(); + GlossariesManagerMock = new Mock(); + LoggerMock = new Mock(); + + var appSettingsStub = new Dictionary { + //{"applicationName", "e-suite test"}, + //{"baseUrl", "https://esuite.test"}, + //{"Smtp:EmailTimeoutHours", "48"}, + //{"Smtp:Server", "127.0.0.1"}, + //{"Smtp:Port", "25"}, + //{"Smtp:FromAddress", "esuitetest@sun-strategy.com"}, + //{"JwtConfig:secret", "Z8p9YKvYnwm62sPLJVdvp3M7bQ5l0UqRGwz95ZqL"}, + //{"JwtConfig:expirationInMinutes", "15"}, + //{"JwtConfig:audience", "test"}, + //{"JwtConfig:issuer", "moq"}, + //{"Sentinel:LoginAttemptTimeoutMinutes", "60"}, + //{"Sentinel:MaxLoginAttempts", "5"} + //{"Sentinel:MaxLoginAttempts", "5"} + {"SigmaFileBrowser:Server","localhost"} + }; + + _configuration = new ConfigurationBuilder() + .AddInMemoryCollection(appSettingsStub!) + .Build(); + + ImportGlossaryHelper = new ImportGlossaryHelper(GlossariesManagerMock.Object); + + GmgProfileImporter = new e_suite.Service.SigmaImporter.GmgProfiles.GmgProfileImporter(SigmaFileBrowserRepositoryMock.Object, GlossariesManagerMock.Object, _configuration, LoggerMock.Object, ImportGlossaryHelper); + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/Helpers/GmgProfileImporterTestBaseWithoutMySql.cs b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/Helpers/GmgProfileImporterTestBaseWithoutMySql.cs new file mode 100644 index 0000000..d79191a --- /dev/null +++ b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/Helpers/GmgProfileImporterTestBaseWithoutMySql.cs @@ -0,0 +1,40 @@ +using e_suite.API.Common; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.GmgProfiles; +using e_suite.Service.SigmaImporter.Helpers; +using e_suite.Service.SigmaImporter.Repository; +using e_suite.UnitTestCore; +using Microsoft.Extensions.Logging; +using Moq; + +namespace SigmaImporter.UnitTests.Helpers; + +public class GmgProfileImporterTestBaseWithoutMySql : TestBase +{ + protected Mock SigmaFileBrowserRepositoryMock { get; set; } = null!; + protected Mock GlossariesManagerMock { get; set; }= null!; + protected Mock CustomFieldManagerMock { get; set; }= null!; + protected Mock LoggerMock { get; set; } = null!; + + protected ImportGlossaryHelper ImportGlossaryHelper { get; set; } = null!; + + protected AuditUserDetails AuditUserDetails = new() + { + Comment = "SigmaImporter Automated import", + UserDisplayName = "MessageProcessor" + }; + + public IGmgProfileImporter GmgProfileImporter { get; set; }= null!; + + public override async Task Setup() + { + await base.Setup(); + SigmaFileBrowserRepositoryMock = new Mock(); + GlossariesManagerMock = new Mock(); + LoggerMock = new Mock(); + + ImportGlossaryHelper = new ImportGlossaryHelper(GlossariesManagerMock.Object); + + GmgProfileImporter = new e_suite.Service.SigmaImporter.GmgProfiles.GmgProfileImporter(SigmaFileBrowserRepositoryMock.Object, GlossariesManagerMock.Object, _configuration, LoggerMock.Object, ImportGlossaryHelper); + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/SigmaImporter.UnitTests.csproj b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/SigmaImporter.UnitTests.csproj new file mode 100644 index 0000000..6173714 --- /dev/null +++ b/e-suite.Service.SigmaImporter/SigmaImporter.UnitTests/SigmaImporter.UnitTests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Service.SigmaImporter/azure-pipelines.yml b/e-suite.Service.SigmaImporter/azure-pipelines.yml new file mode 100644 index 0000000..f97fd08 --- /dev/null +++ b/e-suite.Service.SigmaImporter/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '10' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.sln b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.sln new file mode 100644 index 0000000..9b6dc76 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "e-suite.Service.SigmaImporter", "e-suite.Service.SigmaImporter\e-suite.Service.SigmaImporter.csproj", "{50166BA6-8409-4CF9-AA7A-101327819F3A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8C7C802E-4C02-44C7-922E-7AA36E6E58D6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{D0DB1111-00CF-4304-AF1E-D9AE51E1D641}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SigmaImporter.UnitTests", "SigmaImporter.UnitTests\SigmaImporter.UnitTests.csproj", "{72DB2CDA-4146-4289-9B68-E6F1932AD478}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {50166BA6-8409-4CF9-AA7A-101327819F3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50166BA6-8409-4CF9-AA7A-101327819F3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50166BA6-8409-4CF9-AA7A-101327819F3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50166BA6-8409-4CF9-AA7A-101327819F3A}.Release|Any CPU.Build.0 = Release|Any CPU + {72DB2CDA-4146-4289-9B68-E6F1932AD478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72DB2CDA-4146-4289-9B68-E6F1932AD478}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72DB2CDA-4146-4289-9B68-E6F1932AD478}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72DB2CDA-4146-4289-9B68-E6F1932AD478}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D0DB1111-00CF-4304-AF1E-D9AE51E1D641} = {8C7C802E-4C02-44C7-922E-7AA36E6E58D6} + {72DB2CDA-4146-4289-9B68-E6F1932AD478} = {D0DB1111-00CF-4304-AF1E-D9AE51E1D641} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C814D703-9F26-43BA-AE38-BCDFDB8002B8} + EndGlobalSection +EndGlobal diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Extensions/GuidExtensions.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Extensions/GuidExtensions.cs new file mode 100644 index 0000000..61ae700 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Extensions/GuidExtensions.cs @@ -0,0 +1,20 @@ +using System.Text.Json; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.SigmaImporter.Extensions; + +public static class ObjectExtensions +{ + public static string ToJson(this T obj) + { + return JsonSerializer.Serialize(obj); + } +} + +public static class GuidExtensions +{ + public static GeneralIdRef ToGeneralIdRef(this Guid guid) + { + return new GeneralIdRef { Guid = guid }; + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GlobalSuppressions.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GlobalSuppressions.cs new file mode 100644 index 0000000..3226d51 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")] diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GmgProfiles/GmgProfileImporter.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GmgProfiles/GmgProfileImporter.cs new file mode 100644 index 0000000..6b27baf --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GmgProfiles/GmgProfileImporter.cs @@ -0,0 +1,116 @@ +using System.Data; +using System.Text; +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.extensions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Service.SigmaImporter.Helpers; +using e_suite.Service.SigmaImporter.Repository; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.Service.SigmaImporter.GmgProfiles; + +public class GmgProfileImporter : IGmgProfileImporter +{ + private readonly ISigmaFileBrowserRepository _sigmaFileBrowserURepository; + private readonly IGlossariesManager _glossariesManager; + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + private readonly IImportGlossaryHelper _glossaryHelper; + + public GmgProfileImporter(ISigmaFileBrowserRepository sigmaFileBrowserURepository, IGlossariesManager glossariesManager, IConfiguration configuration, ILogger logger, IImportGlossaryHelper glossaryHelper) + { + _sigmaFileBrowserURepository = sigmaFileBrowserURepository; + _glossariesManager = glossariesManager; + _configuration = configuration; + _logger = logger; + _glossaryHelper = glossaryHelper; + } + + public async Task DoGmgProfileImport(AuditUserDetails auditUserDetails) + { + //Check if there is a MySql database setting present, if not, do nothing. + var server = _configuration.GetConfigValue($"SigmaFileBrowser_SERVER", $"SigmaFileBrowser:Server", ""); + if (string.IsNullOrWhiteSpace(server)) + { + _logger.LogInformation("SigmaFileBrowser_SERVER is not set, skipping import"); + //System is not setup to connect to the mySql database, data import cannot take place. + return; + } + + + var gmgProfileGlossaryItem = await EnsureGmgProfilesSystemGlossaryExists(auditUserDetails) ?? throw new NotFoundException("Gmg Profile Glossary does not exist in e-suite!"); + var gmgProfileGlossaryItemGeneralIdRef = gmgProfileGlossaryItem.ToGeneralIdRef()!; + + //Get the list of GMG Profiles from sigma + var gmgProfiles = await _sigmaFileBrowserURepository.GetActiveGmgProfiles() ?? throw new NotFoundException("The GMG Profile glossary not found from Sigma"); + + var gmgProfileItems = new List(); + foreach (var gmgProfile in gmgProfiles) + { + var existingGmgProfileItem = + gmgProfileGlossaryItem.Children?.SingleOrDefault(x => x.Name == gmgProfile.CompiledName); + if (existingGmgProfileItem == null) + { + //Glossary doesn't exist in e-suite, so import it. + var gmgProfileItem = new NewGlossaryItem + { + Parent = gmgProfileGlossaryItemGeneralIdRef, + Name = gmgProfile.CompiledName + }; + + //Check to ensure the item is not already added. + if (!CheckExists(gmgProfileItems, gmgProfileItem)) + gmgProfileItems.Add(gmgProfileItem); + } + } + + AssertNoDuplicateNames(gmgProfileItems); + + await _glossariesManager.AddGlossaryItems(auditUserDetails, gmgProfileItems, + CancellationToken.None); + } + + private static bool CheckExists(List gmgProfileItems, NewGlossaryItem gmgProfileItem) + { + return gmgProfileItems.Any(x => x.Name == gmgProfileItem.Name); + } + + private void AssertNoDuplicateNames(List gmgProfileItems) + { + var duplicates = gmgProfileItems + .GroupBy(x => x.Name) + .Where(x => x.Count() > 1) + .ToDictionary(x => x.Key, y => y.Count()); + + if (duplicates.Count > 0) + { + var sb = new StringBuilder(); + + foreach (var duplicate in duplicates) + { + sb.AppendFormat("{0}: {1}\r\n", duplicate.Key, duplicate.Value); + } + + throw new DuplicateNameException($"Duplicates found: {sb}"); + } + } + + public readonly Guid GmgProfileGuid = new("BBA078CF-8326-40B8-92EC-ECD9A2017702"); + + private async Task EnsureGmgProfilesSystemGlossaryExists(AuditUserDetails auditUserDetails) + { + + var glossary = new NewGlossaryItem + { + Parent = _glossaryHelper.SystemGlossaryGeneralIdRef, + Guid = GmgProfileGuid, + Name = "GMG Profile" + }; + + return await _glossaryHelper.EnsureGlossaryItemExists(auditUserDetails, glossary); + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GmgProfiles/IGmgProfileImporter.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GmgProfiles/IGmgProfileImporter.cs new file mode 100644 index 0000000..39c2aea --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/GmgProfiles/IGmgProfileImporter.cs @@ -0,0 +1,8 @@ +using e_suite.Database.Audit; + +namespace e_suite.Service.SigmaImporter.GmgProfiles; + +public interface IGmgProfileImporter +{ + Task DoGmgProfileImport(AuditUserDetails auditUserDetails); +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/IImportCustomFieldHelper.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/IImportCustomFieldHelper.cs new file mode 100644 index 0000000..0486e6a --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/IImportCustomFieldHelper.cs @@ -0,0 +1,11 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; + +namespace e_suite.Service.SigmaImporter.Helpers; + +public interface IImportCustomFieldHelper +{ + Task EnsureCustomFieldExists(AuditUserDetails auditUserDetails, CreateCustomField customField); + + Task EnsureCustomFieldsExist(AuditUserDetails auditUserDetails, IEnumerable customFields); +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/IImportGlossaryHelper.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/IImportGlossaryHelper.cs new file mode 100644 index 0000000..0672167 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/IImportGlossaryHelper.cs @@ -0,0 +1,13 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.SigmaImporter.Helpers; + +public interface IImportGlossaryHelper +{ + Task EnsureGlossaryItemExists(AuditUserDetails auditUserDetails, NewGlossaryItem glossary); + Task EnsureGlossaryItemsExists(AuditUserDetails auditUserDetails, IEnumerable glossary); + GeneralIdRef SystemGlossaryGeneralIdRef { get; } + GeneralIdRef PrintSpecificationGlossaryGeneralIdRef { get; } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/ImportCustomerFieldHelper.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/ImportCustomerFieldHelper.cs new file mode 100644 index 0000000..45ed2a3 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/ImportCustomerFieldHelper.cs @@ -0,0 +1,53 @@ +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.Extensions; + +namespace e_suite.Service.SigmaImporter.Helpers; + +public class ImportCustomerFieldHelper : IImportCustomFieldHelper +{ + private readonly ICustomFieldManager _customFieldManager; + + public ImportCustomerFieldHelper(ICustomFieldManager customFieldManager) + { + _customFieldManager = customFieldManager; + } + + public async Task EnsureCustomFieldExists(AuditUserDetails auditUserDetails, CreateCustomField customField) + { + CustomFieldDefinition? field = null; + if (customField.Guid.HasValue) + try + { + field ??= await _customFieldManager.GetFieldAsync(customField.Guid.Value.ToGeneralIdRef(), + CancellationToken.None); + } + catch (NotFoundException) + { + field = null; + } + + try + { + field ??= await _customFieldManager.GetFieldAsync(customField.Name, CancellationToken.None); + } + + catch (NotFoundException) + { + field = null; + } + + if (field == null) + await _customFieldManager.CreateFieldAsync(auditUserDetails, customField, CancellationToken.None); + } + + public async Task EnsureCustomFieldsExist(AuditUserDetails auditUserDetails, IEnumerable customFields) + { + foreach (var customField in customFields) + { + await EnsureCustomFieldExists(auditUserDetails, customField); + } + } +} diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/ImportGlossaryHelper.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/ImportGlossaryHelper.cs new file mode 100644 index 0000000..2b1b361 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Helpers/ImportGlossaryHelper.cs @@ -0,0 +1,57 @@ +using e_suite.API.Common; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.SigmaImporter.Helpers; + +public class ImportGlossaryHelper : IImportGlossaryHelper +{ + private readonly IGlossariesManager _glossariesManager; + + public ImportGlossaryHelper(IGlossariesManager glossariesManager) + { + _glossariesManager = glossariesManager; + } + + public GeneralIdRef SystemGlossaryGeneralIdRef { get; } = new() + { + Guid = new Guid("FA6566F8-B4B0-48C5-9985-336C9284796E") + }; + + public GeneralIdRef PrintSpecificationGlossaryGeneralIdRef { get; } = new() + { + Guid = new Guid("35EB8C23-4528-49A7-A798-B8BAE3B06DAF") + }; + + public async Task EnsureGlossaryItemExists(AuditUserDetails auditUserDetails, NewGlossaryItem glossary) + { + var glossaryGeneralIdRef = new GeneralIdRef + { + Guid = glossary.Guid + }; + + GlossaryItem? glossaryItem; + try + { + glossaryItem = await _glossariesManager.GetGlossaryItem(auditUserDetails, glossaryGeneralIdRef, CancellationToken.None); + } + catch (NotFoundException) + { + await _glossariesManager.AddGlossaryItem(auditUserDetails, glossary, CancellationToken.None); + glossaryItem = await _glossariesManager.GetGlossaryItem(auditUserDetails, glossaryGeneralIdRef, CancellationToken.None); + } + + return glossaryItem!; + } + + public async Task EnsureGlossaryItemsExists(AuditUserDetails auditUserDetails, IEnumerable glossaryItems) + { + foreach (var glossaryItem in glossaryItems) + { + await EnsureGlossaryItemExists(auditUserDetails, glossaryItem); + } + } + +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/IocRegistration.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/IocRegistration.cs new file mode 100644 index 0000000..a71f1a0 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/IocRegistration.cs @@ -0,0 +1,25 @@ +using Autofac; +using e_suite.API.Common; +using e_suite.Service.SigmaImporter.GmgProfiles; +using e_suite.Service.SigmaImporter.Helpers; +using e_suite.Service.SigmaImporter.PrintSpecifications; +using e_suite.Service.SigmaImporter.Repository; + +namespace e_suite.Service.SigmaImporter; + +public static class IocRegistration +{ + public static void RegisterTypes(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/IPrintSpecificationImporter.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/IPrintSpecificationImporter.cs new file mode 100644 index 0000000..8d3c433 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/IPrintSpecificationImporter.cs @@ -0,0 +1,8 @@ +using e_suite.Database.Audit; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public interface IPrintSpecificationImporter +{ + Task DoPrintSpecificationImport(AuditUserDetails auditUserDetails); +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.CustomFields.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.CustomFields.cs new file mode 100644 index 0000000..a196d78 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.CustomFields.cs @@ -0,0 +1,264 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.Extensions; +using eSuite.Core.CustomFields; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter +{ + private readonly Guid _barcodeCommentsGuid = new("965030b7-6b67-4252-b0f2-be1775d11be6"); + private readonly Guid _bwrGuid = new("33603b50-22a3-4cd0-9c1c-d3fac9307bf0"); + private readonly Guid _colours = new("68b1b91c-3b28-47d5-a0a5-17cc72ddcf16"); + private readonly Guid _digitalSupplyMethodGuid = new("a226a708-9e34-422f-a6d7-17f052ef341e"); + private readonly Guid _digitalSupplyCommentsGuid = new("a485041e-49d7-4d51-9c03-572c4728bf2e"); + private readonly Guid _gmgProfileGuid = new("f31edd64-1c41-460c-b4fe-8c47368a782c"); + private readonly Guid _maxDotGuid = new("aa6d4458-2102-4908-ae8f-44dbb04dc6ce"); + private readonly Guid _minDotGuid = new("11015c9b-db6b-4463-9fe5-73ff4f4cce29"); + private readonly Guid _maxInkGuid = new("f5e9d90e-a92c-4765-aba5-23e960a2a73e"); + private readonly Guid _minMagGuid = new("bdef0f6d-fdb0-4cb3-9c66-875190158fa8"); + private readonly Guid _minMultiInkFontGuid = new("adb9ad71-e677-4885-8fd2-745ec56b00ea"); + private readonly Guid _minMultiInkLineGuid = new("2ff3ba40-bf9f-47d7-bcc3-7fde507cb530"); + private readonly Guid _minNegFontGuid = new("7728e67e-d773-4e09-8ec8-fde37d3257a9"); + private readonly Guid _minNegLineGuid = new("c6c47e29-04f1-4293-9540-13458b56fecf"); + private readonly Guid _minPosFontGuid = new("63121c46-92b3-4438-81f3-4efed67d6087"); + private readonly Guid _minPosLineGuid = new("d76f6284-aa9b-4d01-9d38-1a14c236e2f1"); + private readonly Guid _notesGuid = new("c644fce8-8a61-4283-883a-e076354dcbcb"); + private readonly Guid _printProcessGuid = new("1f2aeb33-da9c-4563-be88-177f485e789b"); + private readonly Guid _printProcessCommentsGuid = new("6be92302-b58e-4a6f-8eb4-a801ea844ea6"); + private readonly Guid _sequenceCGuid = new("be6a8649-c63d-4d6d-8a62-acbed7c0847a"); + private readonly Guid _sequenceMGuid = new("deabbe78-66c1-426c-8776-b5ac6ea0a3da"); + private readonly Guid _sequenceYGuid = new("cf312d4b-2e16-406d-9893-fd9844a4d020"); + private readonly Guid _sequenceKGuid = new("5220f156-58f0-4c7e-85b6-6c03d24fa80f"); + private readonly Guid _substrateCommentsGuid = new("eb30ae3f-0244-4582-b066-c43f28022dcf"); + private readonly Guid _techSpecCommentsGuid = new("7600e029-e837-4c0e-ba1d-b3d172d98fd9"); + private readonly Guid _trapGuid = new("cf998656-4003-44fe-b70e-cebae7315f1d"); + private readonly Guid _domainGuid = new("45821c2d-9d6e-4c82-ac57-965755960422"); + + private async Task MakeSureCustomFieldsAreCreated(AuditUserDetails auditUserDetails) + { + + var customFields = new List + { + new() + { + FieldType = FieldType.Glossary, + Name = "GMG Profile", + RefElementId = _gmgProfileGlossaryGuid.ToGeneralIdRef(), + Guid = _gmgProfileGuid, + MaxEntries = 1 + }, + new() + { + FieldType = FieldType.Glossary, + Name = "Digital Supply Method", + RefElementId = _digitalSupplyFormatGlossaryGuid.ToGeneralIdRef(), + Guid = _digitalSupplyMethodGuid, + MaxEntries = 1 + + }, + new() + { + FieldType = FieldType.Glossary, + Name = "Print Process", + RefElementId = _printProcessGlossaryGuid.ToGeneralIdRef(), + Guid = _printProcessGuid, + MaxEntries = 1 + }, + new() + { + FieldType = FieldType.Number, + Name = "Sequence C", + MinEntries = 1, + Guid = _sequenceCGuid, + Parameters = "{ \"step\":\"1\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Sequence M", + MinEntries = 1, + Guid = _sequenceMGuid, + Parameters = "{ \"step\":\"1\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Sequence Y", + MinEntries = 1, + Guid = _sequenceYGuid, + Parameters = "{ \"step\":\"1\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Sequence K", + MinEntries = 1, + Guid = _sequenceKGuid, + Parameters = "{ \"step\":\"1\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Colours", + MinEntries = 1, + Guid = _colours, + Parameters = "{ \"step\":\"1\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Minimum Pos Line", + MinEntries = 1, + Guid = _minPosLineGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Minimum Neg Line", + MinEntries = 1, + Guid = _minNegLineGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Minimum Multi Ink Line", + MinEntries = 1, + Guid = _minMultiInkLineGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Minimum Pos Font", + MinEntries = 1, + Guid = _minPosFontGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Minimum Neg Font", + MinEntries = 1, + Guid = _minNegFontGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Minimum Multi Ink Font", + MinEntries = 1, + Guid = _minMultiInkFontGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Min Dot", + MinEntries = 1, + Guid = _minDotGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Max Dot", + MinEntries = 1, + Guid = _maxDotGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Trap", + MinEntries = 1, + Guid = _trapGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Max Ink", + MinEntries = 1, + Guid = _maxInkGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "BWR", + MinEntries = 1, + Guid = _bwrGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Number, + Name = "Min Mag", + MinEntries = 1, + Guid = _minMagGuid, + Parameters = "{ \"step\":\"0.001\" }" + }, + new() + { + FieldType = FieldType.Text, + Name = "Tech Spec Comments", + MinEntries = 1, + Guid = _techSpecCommentsGuid, + Parameters = "{ \"multiLine\":true }" + }, + new() + { + FieldType = FieldType.Text, + Name = "Print Process Comments", + MinEntries = 1, + Guid = _printProcessCommentsGuid, + Parameters = "{ \"multiLine\":true }" + }, + new() + { + FieldType = FieldType.Text, + Name = "Digital Supply Comments", + MinEntries = 1, + Guid = _digitalSupplyCommentsGuid, + Parameters = "{ \"multiLine\":true }" + }, + new() + { + FieldType = FieldType.Text, + Name = "Barcode Comments", + MinEntries = 1, + Guid = _barcodeCommentsGuid, + Parameters = "{ \"multiLine\":true }" + }, + new() + { + FieldType = FieldType.Text, + Name = "Substrate Comments", + MinEntries = 1, + Guid = _substrateCommentsGuid, + Parameters = "{ \"multiLine\":true }" + }, + new() + { + FieldType = FieldType.Domain, + Name = "Domain", + MinEntries = 0, + Guid = _domainGuid + }, + new() + { + FieldType = FieldType.Text, + Name = "Notes", + MinEntries = 1, + Guid = _notesGuid, + Parameters = "{ \"multiLine\":true }" + } + + }; + + await _importCustomFieldHelper.EnsureCustomFieldsExist(auditUserDetails, customFields); + } +} diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.CustomForm.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.CustomForm.cs new file mode 100644 index 0000000..4021427 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.CustomForm.cs @@ -0,0 +1,69 @@ +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.Extensions; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter +{ + public readonly Guid PrintSpecificationFormGuid = new("e84d8a56-b025-44b9-80b3-bf9324644e23"); + public readonly Guid GeneralPrintSpecificationGlossaryItemGuid = new("ef1be548-ec7f-4c16-b2fe-d8f89b5ead54"); + public readonly Guid PrintSpecificationCustomFieldGuid = new("8D910089-3079-4A29-ABAD-8DDF82DB6DBB"); + + private async Task MakeSurePrintSpecCustomFormCreated(AuditUserDetails auditUserDetails) + { + GeneralIdRef printSpecificationFormRefId = PrintSpecificationFormGuid.ToGeneralIdRef(); + GetFormTemplate printSpecificationFormTemplate; + try + { + printSpecificationFormTemplate = + await _formsManager.GetFormTemplateAsync(printSpecificationFormRefId, CancellationToken.None); + } + catch (NotFoundException) + { + var createFormTemplate = new CreateFormTemplate + { + Guid = PrintSpecificationFormGuid, + Name = "General Print Specification", + Definition = GetDefinitionFromFile() + }; + await _formsManager.CreateFormTemplateAsync(auditUserDetails, createFormTemplate, CancellationToken.None); + printSpecificationFormTemplate = + await _formsManager.GetFormTemplateAsync(printSpecificationFormRefId, CancellationToken.None); + + var glossary = new NewGlossaryItem + { + Parent = _importGlossaryHelper.PrintSpecificationGlossaryGeneralIdRef, + Guid = GeneralPrintSpecificationGlossaryItemGuid, + Name = createFormTemplate.Name, + CustomFieldValues = + [ + new CustomFieldValues + { + Id = PrintSpecificationCustomFieldGuid.ToGeneralIdRef(), + Values = + [ + new CustomFieldValue + { + DisplayValue = printSpecificationFormTemplate.Name, + Value = printSpecificationFormTemplate.Guid.ToGeneralIdRef().ToJson() + } + ] + } + ] + }; + + await _importGlossaryHelper.EnsureGlossaryItemExists(auditUserDetails, glossary); + } + + return printSpecificationFormTemplate; + } + + private string GetDefinitionFromFile() + { + var generalPrintSpecificationFormTemplateDefinition = File.ReadAllText("Resources/GeneralPrintSpecificationFormTemplateDefintion.txt"); + return generalPrintSpecificationFormTemplateDefinition; + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.GlossaryItems.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.GlossaryItems.cs new file mode 100644 index 0000000..253c5ef --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.GlossaryItems.cs @@ -0,0 +1,133 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter +{ + private readonly Guid _gmgProfileGlossaryGuid = new("BBA078CF-8326-40B8-92EC-ECD9A2017702"); + private readonly Guid _digitalSupplyFormatGlossaryGuid = new("28C9D529-0475-4B86-BDF3-453D4589582F"); + private readonly Guid _printProcessGlossaryGuid = new("73DB3496-151D-4798-BB77-B4B73B0E236E"); + + private async Task MakeSureSystemGlossariesAreCreated(AuditUserDetails auditUserDetails) + { + await EnsureGmgProfileGlossaryExists(auditUserDetails); + await EnsureDigitalSupplyFormatExists(auditUserDetails); + await EnsurePrintProcessExists(auditUserDetails); + } + + private async Task EnsureGmgProfileGlossaryExists(AuditUserDetails auditUserDetails) + { + var glossary = new NewGlossaryItem + { + Parent = _importGlossaryHelper.SystemGlossaryGeneralIdRef, + Guid = _gmgProfileGlossaryGuid, + Name = "GMG Profile" + }; + + await _importGlossaryHelper.EnsureGlossaryItemExists(auditUserDetails, glossary); + } + + private async Task EnsureDigitalSupplyFormatExists(AuditUserDetails auditUserDetails) + { + var glossary = new NewGlossaryItem + { + Parent = _importGlossaryHelper.SystemGlossaryGeneralIdRef, + Guid = _digitalSupplyFormatGlossaryGuid, + Name = "Digital Supply Format" + }; + + + var digitalSupplyFormat = await _importGlossaryHelper.EnsureGlossaryItemExists(auditUserDetails, glossary); + await EnsureDigitalSupplyFormatItemsExists(auditUserDetails, digitalSupplyFormat); + } + + private static readonly Guid PdfGuid = new("3EC35635-C125-4B17-9053-D201ACF1CBDB"); + private static readonly Guid IllustratorGuid = new("0979DB47-5409-4CA5-A9B8-ADDF10593F87"); + private static readonly Guid EskoGuid = new("76862192-F732-4292-84D8-DD45D2B169CD"); + private static readonly Guid ArtProGuid = new("0D970422-F1B1-4049-88C4-50A999D8E388"); + + private async Task EnsureDigitalSupplyFormatItemsExists(AuditUserDetails auditUserDetails, + GlossaryItem? digitalSupplyFormat) + { + var parent = digitalSupplyFormat.ToGeneralIdRef()!; + + var glossaryItems = new List + { + new() + { + Parent = parent, + Guid = PdfGuid, + Name = "PDF" + }, + new() + { + Parent = parent, + Guid = IllustratorGuid, + Name = "Illustrator" + }, + new() + { + Parent = parent, + Guid = EskoGuid, + Name = "Esko" + }, + new() + { + Parent = parent, + Guid = ArtProGuid, + Name = "ArtPro" + } + }; + + await _importGlossaryHelper.EnsureGlossaryItemsExists(auditUserDetails, glossaryItems); + } + + private async Task EnsurePrintProcessExists(AuditUserDetails auditUserDetails) + { + var glossary = new NewGlossaryItem + { + Parent = _importGlossaryHelper.SystemGlossaryGeneralIdRef, + Guid = _printProcessGlossaryGuid, + Name = "Print Process" + }; + + var printProcess = await _importGlossaryHelper.EnsureGlossaryItemExists(auditUserDetails, glossary); + + await EnsurePrintProcessItemsExists(auditUserDetails, printProcess); + } + + private async Task EnsurePrintProcessItemsExists(AuditUserDetails auditUserDetails, GlossaryItem printProcess) + { + try + { + var parent = printProcess.ToGeneralIdRef()!; + + var activePrintProcesses = await _sigmaFtpuRepository.GetActivePrintProcesses(); + + var glossaryItems = new List(); + foreach (var printProcessName in activePrintProcesses) + { + var existing = + printProcess.Children?.SingleOrDefault(x => x.Name == printProcessName); + + if (existing == null) + { + glossaryItems.Add(new NewGlossaryItem + { + Guid = Guid.NewGuid(), + Name = printProcessName, + Parent = parent + }); + } + } + + await _importGlossaryHelper.EnsureGlossaryItemsExists(auditUserDetails, glossaryItems); + } + catch (Exception) + { + throw; + } + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.ImportDomains.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.ImportDomains.cs new file mode 100644 index 0000000..6c44a85 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.ImportDomains.cs @@ -0,0 +1,82 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.Repository; +using e_suite.Utilities.Pagination; +using e_suite.Service.SigmaImporter.Extensions; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter : IPrintSpecificationImporter +{ + private Dictionary _hostnameDictionary = new Dictionary(); + + private async Task> ImportDomains(AuditUserDetails auditUserDetails) + { + var eSuiteDomains = await LoadExistingDomains(); + var sigmaDomains = await LoadSigmaDomains(); + + await AddMissingDomainsToESuite(eSuiteDomains, sigmaDomains, auditUserDetails); + + return eSuiteDomains; + } + + private async Task AddMissingDomainsToESuite(List eSuiteDomains, List sigmaDomains, AuditUserDetails auditUserDetails) + { + foreach (var sigmaDomain in sigmaDomains) + { + var esuiteDomain = FindESuiteDomainByHostname(eSuiteDomains, sigmaDomain.Hostname); + if (esuiteDomain != null) + continue; + + //Need to add the new domain to esuite here. + var createDomain = new CreateDomain + { + Name = sigmaDomain.Name, + SunriseHostName = sigmaDomain.Hostname, + SigmaId = sigmaDomain.Id, + Guid = Guid.NewGuid() + }; + + await _domainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None); + var newDomain = await _domainManager.GetDomainAsync(createDomain.Guid.Value.ToGeneralIdRef(), CancellationToken.None); + + eSuiteDomains.Add(newDomain); + } + } + + private GetDomain? FindESuiteDomainByHostname(List eSuiteDomains, string sigmaDomainHostname) + { + return eSuiteDomains.FirstOrDefault(eSuiteDomain => eSuiteDomain.SunriseHostName.Equals(sigmaDomainHostname)); + } + + private async Task> LoadSigmaDomains() + { + await PrepareHostnameDictionary(); + + var sigmaDomains = (await _sigmaRepository.GetDomains()).ToList(); + foreach (var sigmaDomain in sigmaDomains) + { + if (_hostnameDictionary.TryGetValue(sigmaDomain.Tla, out var hostname)) + sigmaDomain.Hostname = hostname; + } + + return sigmaDomains; + } + + private async Task> LoadExistingDomains() + { + var domainList = (await _domainManager.GetDomainsAsync(new Paging() { Page = 0 }, CancellationToken.None)).Data.ToList(); + + return domainList; + } + + private async Task PrepareHostnameDictionary() + { + _hostnameDictionary.Clear(); + var tlaHostNames = await _airlockRepository.GetActivePrintSpecifications(); + foreach (var tlaHostname in tlaHostNames) + { + _hostnameDictionary.Add(tlaHostname.Tla, tlaHostname.Hostname); + } + } +} diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.ImportPrintSpecifications.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.ImportPrintSpecifications.cs new file mode 100644 index 0000000..cba6633 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.ImportPrintSpecifications.cs @@ -0,0 +1,450 @@ +using System.Text.Json; +using e_suite.API.Common.exceptions; +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Extensions; +using e_suite.Database.Core.Tables.Forms; +using e_suite.Database.Core.Tables.Printer; +using e_suite.Service.SigmaImporter.Extensions; +using e_suite.Service.SigmaImporter.Repository; +using e_suite.Utilities.Pagination; +using eSuite.Core.Miscellaneous; +using Microsoft.Extensions.Logging; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter +{ + private async Task ImportPrintSpecifications(AuditUserDetails auditUserDetails, + GetFormTemplate specificationFormTemplate, List eSuiteDomains) + { + var specificationFormTemplateGeneralIdRef = specificationFormTemplate.ToGeneralIdRef()!; + + var printSpecifications = (await _sigmaFtpuRepository.GetActivePrintSpecifications()).ToList() ?? + throw new NotFoundException("The Print Specifications not found from Sigma"); + var printSpecificationDomains = (await _sigmaFtpuRepository.GetActivePrintSpecificationDomains()).ToList() ?? + throw new NotFoundException("Unable to load the print specification domains from Sigma"); + + await PrepareSiteDictionary(auditUserDetails, printSpecifications); + await PrepareProcessDictionary(auditUserDetails, printSpecifications); + + var specifications = + await _specificationManager.GetSpecifications(new Paging() { Page = 0 }, CancellationToken.None); + + var additionList = new List(); + var editSpecificationList = new List(); + var editFormInstanceList = new List(); + + var batchSize = 100; + + while (printSpecifications.Count>0) + { + var batch = printSpecifications.Take(batchSize).ToArray(); + _logger.LogInformation("{DateTime} Processing specifications batch of {BatchSize}, {Total} left to process.", _clock.GetNow, batch.Length, printSpecifications.Count); + printSpecifications.RemoveAll(x => batch.Contains(x)); + + var sigmaIds = batch.Select(x => x.SigmaId).ToArray(); + var specs = specifications.Data.Where(x => x.SigmaId.HasValue & sigmaIds.Contains( x.SigmaId!.Value)); + + var formInstances = await _formsManager.GetFormInstanceAsync(specs.Select(x => x.FormInstanceId), CancellationToken.None); + + + foreach (var printSpecification in batch) + { + var specification = specifications.Data.SingleOrDefault(x => x.SigmaId == printSpecification.SigmaId); + if (specification != null) + { + var specificationHasChanges = false; + + specificationHasChanges = specificationHasChanges | !specification.Name.Equals(printSpecification.Name, StringComparison.InvariantCulture); + + //Todo figure out if there are any changes to the specification domains. + + if (specificationHasChanges) + { + editSpecificationList.Add(new EditSpecification + { + Id = specification.ToGeneralIdRef()!, + Name = printSpecification.Name, + FormInstanceId = specification.FormInstanceId, + Site = specification.Site, + //Domains = GetIncludedDomainsFromSigma(printSpecification, printSpecificationDomains, eSuiteDomains)//Todo upgrade this to be present the updated list of domains instead of the current domains. + }); + } + + var formInstance = formInstances.SingleOrDefault(x => x.Id == specification.FormInstanceId.Id || x.Guid == specification.FormInstanceId.Guid); + //var formInstance = await _formsManager.GetFormInstanceAsync(specification.FormInstanceId, CancellationToken.None); + + if (formInstance != null) + { + var editFormInstance = new EditFormInstance(formInstance); + var edited = false; + + EditCustomFieldValue(editFormInstance, _barcodeCommentsGuid, printSpecification.Barcode, ref edited); + EditCustomFieldValue(editFormInstance, _bwrGuid, printSpecification.Bwr ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _colours, printSpecification.Colours, ref edited); + EditCustomFieldValue(editFormInstance, _digitalSupplyMethodGuid, TranslateSupplyMethod(printSpecification.SupplyMethod), ref edited); + EditCustomFieldValue(editFormInstance, _digitalSupplyCommentsGuid, printSpecification.DigitalSupply, ref edited); + EditCustomFieldValue(editFormInstance, _gmgProfileGuid, LookupGmgProfileGlossaryGuid(printSpecification.GmgFk), ref edited); + EditCustomFieldValue(editFormInstance, _maxDotGuid, printSpecification.Maxdot ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minDotGuid, printSpecification.Mindot ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _maxInkGuid, printSpecification.MaxInk ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minMagGuid, printSpecification.MinMag ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minMultiInkFontGuid, printSpecification.Mmif ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minMultiInkLineGuid, printSpecification.Mmil ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minNegFontGuid, printSpecification.Mnf ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minNegLineGuid, printSpecification.Mnl ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minPosFontGuid, printSpecification.Mpf ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _minPosLineGuid, printSpecification.Mpl ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _notesGuid, printSpecification.Notes, ref edited); + EditCustomFieldValue(editFormInstance, _printProcessGuid, LookupProcessGlossaryItem(printSpecification.Process), ref edited); + EditCustomFieldValue(editFormInstance, _printProcessCommentsGuid, printSpecification.PrintProcess, ref edited); + EditCustomFieldValue(editFormInstance, _sequenceCGuid, printSpecification.SequenceC, ref edited); + EditCustomFieldValue(editFormInstance, _sequenceMGuid, printSpecification.SequenceM, ref edited); + EditCustomFieldValue(editFormInstance, _sequenceYGuid, printSpecification.SequenceY, ref edited); + EditCustomFieldValue(editFormInstance, _sequenceKGuid, printSpecification.SequenceK, ref edited); + EditCustomFieldValue(editFormInstance, _substrateCommentsGuid, printSpecification.Substrate, ref edited); + EditCustomFieldValue(editFormInstance, _techSpecCommentsGuid, printSpecification.TechSpec, ref edited); + EditCustomFieldValue(editFormInstance, _trapGuid, printSpecification.Trap ?? 0, ref edited); + EditCustomFieldValue(editFormInstance, _domainGuid, GetIncludedDomainsFromSigma(printSpecification, printSpecificationDomains, eSuiteDomains), ref edited); + + if (edited) + { + editFormInstanceList.Add(editFormInstance); + } + } + } + else + additionList.Add(printSpecification); + } + + if (editFormInstanceList.Count > 0) + { + foreach (var editFormInstance in editFormInstanceList) + await _formsManager.EditFormInstanceAsync(auditUserDetails, editFormInstance, CancellationToken.None); + } + + if (editSpecificationList.Count > 0) + { + await _specificationManager.EditSpecification(auditUserDetails, editSpecificationList, false, + CancellationToken.None); + } + + if (additionList.Count > 0) + { + await AddNewPrintSpecs(auditUserDetails, specificationFormTemplate, additionList, + specificationFormTemplateGeneralIdRef, printSpecificationDomains, eSuiteDomains); + } + + editFormInstanceList.Clear(); + editSpecificationList.Clear(); + additionList.Clear(); + } + } + + private static void EditCustomFieldValue(EditFormInstance editFormInstance, Guid fieldId, object? value, ref bool edited) + { + + //todo check this will cope with an array of values. + var fieldIdRef = fieldId.ToGeneralIdRef(); + + foreach (var field in editFormInstance.CustomFieldValues) + { + if (field.Id.Equals(fieldIdRef)) + { + if (value is IEnumerable enumerableCustomFieldValues) + { + edited = true; + field.Values = [..enumerableCustomFieldValues]; + + return; + } + + var firstValue = field.Values.First(); + if (value is CustomFieldValue customFieldValue) + { + var valueAsGeneralIdRef = JsonSerializer.Deserialize(customFieldValue.Value.ToString()!)!; + if (!valueAsGeneralIdRef.Equals(firstValue.Value)) + { + edited = true; + field.Values = [customFieldValue]; + return; //As we've edited the field, we can shortcut out of the method here for performance. + } + } + else + { + var newValue = ConvertValueToString( value ); + if (!firstValue.Value.ToString()!.Equals(newValue)) + { + edited = true; + field.Values = + [ + new CustomFieldValue + { + DisplayValue = value?.ToString() ?? string.Empty, + Value = newValue + } + ]; + } + } + + //As the field has been located, there's no need to search for a second instance of the same field. + return; + } + } + + if (value != null) + { + //If we get here, the field wasn't existing on the form, so will need to be added. + var newFieldValue = AddCustomFieldValue(fieldId, value); + editFormInstance.CustomFieldValues.Add(newFieldValue); + edited = true; + } + } + + private static string ConvertValueToString(object? value) + { + return value?.ToString()?.ReplaceLineEndings("\n").Trim() ?? string.Empty; + } + + private async Task AddNewPrintSpecs(AuditUserDetails auditUserDetails, GetFormTemplate specificationFormTemplate, + List additionList, GeneralIdRef specificationFormTemplateGeneralIdRef, List printSpecDomains, List eSuiteDomains) + { + try + { + var formInstanceDictionary = + await PrepareFormInstanceDictionary(auditUserDetails, specificationFormTemplate, additionList, specificationFormTemplateGeneralIdRef, printSpecDomains, eSuiteDomains); + + var newSpecifications = formInstanceDictionary.Select(x => + new CreateSpecification + { + Name = x.Key.Name, + FormInstanceId = x.Value.Guid!.Value.ToGeneralIdRef(), + Site = siteGeneralIdRefs[x.Key.SiteId], + SigmaId = x.Key.SigmaId, + //Domains = GetIncludedDomainsFromSigma(x.Key, printSpecDomains, eSuiteDomains) + } + ).ToArray(); + + await _specificationManager.CreateSpecification(auditUserDetails, newSpecifications, false, + CancellationToken.None); + } + catch (Exception ex) + { + _logger.LogError("AddNewPrintSpecs failed: {message}", ex.Message); + throw; + } + } + + private List GetIncludedDomainsFromSigma(SigmaPrintSpecification sigmaPrintSpecification, List printSpecDomains, List eSuiteDomains) + { + var includedDomains = new List(); + + foreach (var printSpecDomain in printSpecDomains.Where(x => x.PrintSpecId == sigmaPrintSpecification.SigmaId)) + { + var domain = FindDomainBySigmaId(eSuiteDomains, printSpecDomain.ClientId); + if (domain != null) + includedDomains.Add( new CustomFieldValue + { + DisplayValue = domain.Name, + Value = domain.ToGeneralIdRef().ToJson() + } ); + } + + return includedDomains; + } + + private GetDomain? FindDomainBySigmaId(List eSuiteDomains, long clientId) + { + foreach (var domain in eSuiteDomains) + { + if (domain.SigmaId == clientId) + return domain; + } + + return null; + } + + private async Task> PrepareFormInstanceDictionary(AuditUserDetails auditUserDetails, + GetFormTemplate specificationFormTemplate, List printSpecifications, + GeneralIdRef specificationFormTemplateGeneralIdRef, List printSpecDomains, List eSuiteDomains) + { + var formInstanceDictionary = new Dictionary(); + + foreach (var printSpecification in printSpecifications) + { + formInstanceDictionary.Add(printSpecification, AddFormInstanceToDictionary(specificationFormTemplate, specificationFormTemplateGeneralIdRef, printSpecification, printSpecDomains, eSuiteDomains)); + } + + await _formsManager.CreateFormInstancesAsync(auditUserDetails, formInstanceDictionary.Values, CancellationToken.None); + + return formInstanceDictionary; + } + + private CreateFormInstance AddFormInstanceToDictionary(GetFormTemplate specificationFormTemplate, + GeneralIdRef specificationFormTemplateGeneralIdRef, SigmaPrintSpecification printSpecification, List printSpecDomains, List eSuiteDomains) + { + var createFormInstance = new CreateFormInstance + { + TemplateId = specificationFormTemplateGeneralIdRef, + Version = specificationFormTemplate.Version, + CustomFieldValues = + [ + AddCustomFieldValue(_barcodeCommentsGuid, printSpecification.Barcode), + AddCustomFieldValue(_bwrGuid, printSpecification.Bwr ?? 0), + AddCustomFieldValue(_colours, printSpecification.Colours), + AddCustomFieldValue(_digitalSupplyMethodGuid,TranslateSupplyMethod(printSpecification.SupplyMethod)), + AddCustomFieldValue(_digitalSupplyCommentsGuid, printSpecification.DigitalSupply), + AddCustomFieldValue(_gmgProfileGuid, LookupGmgProfileGlossaryGuid(printSpecification.GmgFk)), + AddCustomFieldValue(_maxDotGuid, printSpecification.Maxdot ?? 0), + AddCustomFieldValue(_minDotGuid, printSpecification.Mindot ?? 0), + AddCustomFieldValue(_maxInkGuid, printSpecification.MaxInk ?? 0), + AddCustomFieldValue(_minMagGuid, printSpecification.MinMag ?? 0), + AddCustomFieldValue(_minMultiInkFontGuid, printSpecification.Mmif ?? 0), + AddCustomFieldValue(_minMultiInkLineGuid, printSpecification.Mmil ?? 0), + AddCustomFieldValue(_minNegFontGuid, printSpecification.Mnf ?? 0), + AddCustomFieldValue(_minNegLineGuid, printSpecification.Mnl ?? 0), + AddCustomFieldValue(_minPosFontGuid, printSpecification.Mpf ?? 0), + AddCustomFieldValue(_minPosLineGuid, printSpecification.Mpl ?? 0), + AddCustomFieldValue(_notesGuid, printSpecification.Notes), + AddCustomFieldValue(_printProcessGuid,LookupProcessGlossaryItem(printSpecification.Process)), + AddCustomFieldValue(_printProcessCommentsGuid, printSpecification.PrintProcess), + AddCustomFieldValue(_sequenceCGuid, printSpecification.SequenceC), + AddCustomFieldValue(_sequenceMGuid, printSpecification.SequenceM), + AddCustomFieldValue(_sequenceYGuid, printSpecification.SequenceY), + AddCustomFieldValue(_sequenceKGuid, printSpecification.SequenceK), + AddCustomFieldValue(_substrateCommentsGuid, printSpecification.Substrate), + AddCustomFieldValue(_techSpecCommentsGuid, printSpecification.TechSpec), + AddCustomFieldValue(_trapGuid, printSpecification.Trap ?? 0), + AddCustomFieldValue(_domainGuid, GetIncludedDomainsFromSigma(printSpecification, printSpecDomains, eSuiteDomains)) + ], + Guid = Guid.NewGuid() + }; + + return createFormInstance; + } + + private readonly Dictionary siteGeneralIdRefs = []; + + private async Task PrepareSiteDictionary(AuditUserDetails auditUserDetails, List printSpecifications) + { + siteGeneralIdRefs.Clear(); + await LoadExistingSites(); + await CreateAndInsertMissingSites(auditUserDetails, printSpecifications); + } + + private async Task CreateAndInsertMissingSites(AuditUserDetails auditUserDetails, List printSpecifications) + { + var newSites = new List(); + foreach (var printSpecification in printSpecifications) + { + if (siteGeneralIdRefs.ContainsKey(printSpecification.SiteId)) + { + continue; + } + + var newSite = new CreateSite + { + OrganisationId = _sigmaOrganisationGeneralRefId, + Name = printSpecification.PrinterName, + Address = printSpecification.PrinterAddress, + SigmaId = printSpecification.SiteId, + Guid = Guid.NewGuid() + }; + + var siteGeneralIdRef = newSite.Guid.Value.ToGeneralIdRef(); + siteGeneralIdRefs.Add(newSite.SigmaId.Value, siteGeneralIdRef); + newSites.Add(newSite); + } + await _siteManager.CreateSites(auditUserDetails, newSites, false, CancellationToken.None); + } + + private async Task LoadExistingSites() + { + var sigmaOrganisation= await _organisationsManager.GetOrganisation(SigmaOrganisationGuid.ToGeneralIdRef(), CancellationToken.None); + var existingSites = await _siteManager.GetSites(new Paging + { + Page=0 + }, CancellationToken.None); + + foreach (var existingSite in existingSites.Data.Where( x => x.SigmaId != null)) + { + siteGeneralIdRefs.Add(existingSite.SigmaId!.Value, existingSite.ToGeneralIdRef()!); + } + } + + private CustomFieldValue? LookupGmgProfileGlossaryGuid(int printSpecificationGmgFk) + { + try + { + return _gmgProfileDictionary[printSpecificationGmgFk]; + } + catch (Exception) + { + return null; + } + } + + private CustomFieldValue? LookupProcessGlossaryItem(string printSpecificationProcess) + { + try + { + return _printProcessDictionary[printSpecificationProcess.ToLowerInvariant().Trim()]; + } + catch (Exception) + { + return null; + } + } + + private CustomFieldValue? TranslateSupplyMethod(string printSpecificationSupplyMethod) + { + try + { + return _supplyMethods[printSpecificationSupplyMethod.ToLower()]; + } + catch (Exception) + { + return null; + } + } + + private static CustomFieldValues AddCustomFieldValue(Guid guid, object? value) + { + if (value is IEnumerable enumerableCustomFieldValues) + { + var values = new CustomFieldValues + { + Id = guid.ToGeneralIdRef(), + }; + values.Values.AddRange(enumerableCustomFieldValues); + + return values; + } + + if (value is CustomFieldValue customFieldValue) + { + return new CustomFieldValues + { + Id = guid.ToGeneralIdRef(), + Values = + [ + customFieldValue + ] + }; + } + + return new CustomFieldValues + { + Id = guid.ToGeneralIdRef(), + Values = + [ + new CustomFieldValue + { + DisplayValue = value?.ToString() ?? string.Empty, + Value = ConvertValueToString( value ) + } + ] + }; + } +} diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.Organisation.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.Organisation.cs new file mode 100644 index 0000000..25c4a8e --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.Organisation.cs @@ -0,0 +1,31 @@ +using e_suite.API.Common.models; +using e_suite.Database.Audit; +using e_suite.Database.Core.Models; +using e_suite.Service.SigmaImporter.Extensions; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter +{ + private static readonly Guid SigmaOrganisationGuid = new("c856858e-4ea9-484e-8110-73579f72dba2"); + private readonly GeneralIdRef _sigmaOrganisationGeneralRefId = SigmaOrganisationGuid.ToGeneralIdRef(); + + private async Task MakeSureSigmaOrganisationExists(AuditUserDetails auditUserDetails) + { + var organisation = await _organisationsManager.GetOrganisation(_sigmaOrganisationGeneralRefId, CancellationToken.None); + + if (organisation == null) + { + var addOrganisationDto = new CreateOrganisation + { + Name = "Sigma", + Guid = SigmaOrganisationGuid, + Address = "n/a", + Status = OrganisationStatus.Active + }; + + await _organisationsManager.AddOrganisation(auditUserDetails, addOrganisationDto, false, CancellationToken.None); + } + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.cs new file mode 100644 index 0000000..0b59fc9 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/PrintSpecifications/PrintSpecificationImporter.cs @@ -0,0 +1,164 @@ +using e_suite.API.Common; +using e_suite.API.Common.extensions; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.Helpers; +using e_suite.Service.SigmaImporter.Repository; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using e_suite.API.Common.exceptions; +using e_suite.Service.SigmaImporter.Extensions; +using e_suite.API.Common.models; +using eSuite.Core.Clock; +using eSuite.Core.Miscellaneous; + +namespace e_suite.Service.SigmaImporter.PrintSpecifications; + +public partial class PrintSpecificationImporter : IPrintSpecificationImporter +{ + private readonly IImportGlossaryHelper _importGlossaryHelper; + private readonly IImportCustomFieldHelper _importCustomFieldHelper; + private readonly IFormsManager _formsManager; + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + private readonly ISigmaFtpuRepository _sigmaFtpuRepository; + private readonly ISigmaFileBrowserRepository _sigmaFileBrowserURepository; + private readonly ISpecificationManager _specificationManager; + private readonly ISiteManager _siteManager; + private readonly IGlossariesManager _glossariesManager; + private readonly IOrganisationsManager _organisationsManager; + private readonly ISigmaAirlockRepository _airlockRepository; + private readonly ISigmaRepository _sigmaRepository; + private readonly IDomainManager _domainManager; + private readonly IEFlowSync _eFlowSync; + private readonly IClock _clock; + + public PrintSpecificationImporter(IImportGlossaryHelper importGlossaryHelper, + IImportCustomFieldHelper importCustomFieldHelper, IFormsManager formsManager, IConfiguration configuration, ILogger logger, ISigmaFtpuRepository sigmaFtpuRepository, ISpecificationManager specificationManager, ISiteManager siteManager, ISigmaFileBrowserRepository sigmaFileBrowserURepository, IGlossariesManager glossariesManager, IOrganisationsManager organisationsManager, ISigmaAirlockRepository airlockRepository, ISigmaRepository sigmaRepository, IDomainManager domainManager, IEFlowSync eFlowSync, IClock clock) + { + _importGlossaryHelper = importGlossaryHelper; + _importCustomFieldHelper = importCustomFieldHelper; + _formsManager = formsManager; + _configuration = configuration; + _logger = logger; + _sigmaFtpuRepository = sigmaFtpuRepository; + _specificationManager = specificationManager; + _siteManager = siteManager; + _sigmaFileBrowserURepository = sigmaFileBrowserURepository; + _glossariesManager = glossariesManager; + _organisationsManager = organisationsManager; + _airlockRepository = airlockRepository; + _sigmaRepository = sigmaRepository; + _domainManager = domainManager; + _eFlowSync = eFlowSync; + _clock = clock; + } + + public async Task DoPrintSpecificationImport(AuditUserDetails auditUserDetails) + { + var server = _configuration.GetConfigValue($"SigmaFTPU_SERVER", $"SigmaFTPU:Server", ""); + if (string.IsNullOrWhiteSpace(server)) + { + _logger.LogInformation("SigmaFTPU_SERVER is not set, skipping import"); + //System is not setup to connect to the mySql database, data import cannot take place. + return; + } + + await MakeSureSystemGlossariesAreCreated(auditUserDetails); + await MakeSureCustomFieldsAreCreated(auditUserDetails); + await MakeSureSigmaOrganisationExists(auditUserDetails); + var specificationFormTemplate = await MakeSurePrintSpecCustomFormCreated(auditUserDetails); + await PrepareSupplyMethodsDictionary(); + await PrepareGmgProfileDictionary(auditUserDetails); + var eSuiteDomains = await ImportDomains(auditUserDetails); + await ImportPrintSpecifications(auditUserDetails, specificationFormTemplate, eSuiteDomains); + await _eFlowSync.SyncEFlowPrinterCategories([]); + } + + private readonly Dictionary _supplyMethods = []; + + private Task PrepareSupplyMethodsDictionary() + { + if (_supplyMethods.Count == 0) + { + _supplyMethods.Add("pdf", new CustomFieldValue { Value = PdfGuid.ToGeneralIdRef().ToJson(), DisplayValue = "PDF" }); + _supplyMethods.Add("illustrator", new CustomFieldValue{ Value = IllustratorGuid.ToGeneralIdRef().ToJson(), DisplayValue = "Illustrator" }); + _supplyMethods.Add("esko", new CustomFieldValue { Value = EskoGuid.ToGeneralIdRef().ToJson(), DisplayValue = "Esko" }); + _supplyMethods.Add("artpro", new CustomFieldValue { Value = ArtProGuid.ToGeneralIdRef().ToJson(), DisplayValue = "ArtPro" }); + } + + return Task.CompletedTask; + } + + + private readonly Dictionary _printProcessDictionary = []; + + private async Task PrepareProcessDictionary(AuditUserDetails auditUserDetails, List printSpecifications) + { + var printProcessGlossaryGeneralIdRef = _printProcessGlossaryGuid.ToGeneralIdRef(); + var printProcessGlossary = await _glossariesManager.GetGlossaryItem(auditUserDetails, printProcessGlossaryGeneralIdRef, CancellationToken.None); + AddItemsToPrintProcessDictionary(printProcessGlossary!); + + var newProcesses = new List(); + foreach (var printSpecification in printSpecifications) + { + if (!string.IsNullOrWhiteSpace(printSpecification.Process) && !_printProcessDictionary.ContainsKey(printSpecification.Process.ToLowerInvariant().Trim())) + { + var newProcess = new NewGlossaryItem + { + Name = printSpecification.Process.Trim(), + Guid = Guid.NewGuid(), + Parent = printProcessGlossaryGeneralIdRef + }; + newProcesses.Add(newProcess); + _printProcessDictionary.Add(newProcess.Name.ToLowerInvariant().Trim(), new CustomFieldValue + { + DisplayValue = newProcess.Name, + Value = newProcess.Guid!.Value.ToGeneralIdRef().ToJson() + }); + } + } + + await _glossariesManager.AddGlossaryItems(auditUserDetails, newProcesses, CancellationToken.None); + } + + private void AddItemsToPrintProcessDictionary(GlossaryItem items) + { + foreach (var printProcessItem in items.Children!) + { + if (!_printProcessDictionary.ContainsKey(printProcessItem.Name.ToLowerInvariant().Trim())) + { + _printProcessDictionary.Add(printProcessItem.Name.ToLowerInvariant().Trim(), new CustomFieldValue + { + DisplayValue = printProcessItem.Name, + Value = printProcessItem.Guid.ToGeneralIdRef().ToJson() + }); + } + } + } + + public readonly Guid GmgProfileGuid = new("BBA078CF-8326-40B8-92EC-ECD9A2017702"); + private readonly Dictionary _gmgProfileDictionary = []; + + private async Task PrepareGmgProfileDictionary(AuditUserDetails auditUserDetails) + { + var glossaryGeneralIdRef = GmgProfileGuid.ToGeneralIdRef(); + var gmgProfileGlossaryItem = + await _glossariesManager.GetGlossaryItem(auditUserDetails, glossaryGeneralIdRef, CancellationToken.None) ?? throw new NotFoundException("Unable to find GMG Profile glossary"); + + var gmgProfiles = (await _sigmaFileBrowserURepository.GetActiveGmgProfiles()).ToList(); + + foreach (var gmgProfile in gmgProfiles) + { + var existingGmgProfileItem = gmgProfileGlossaryItem.Children?.Single(x => x.Name == gmgProfile.CompiledName) ?? throw new NotFoundException(); + + if (!_gmgProfileDictionary.ContainsKey(gmgProfile.Id)) + { + _gmgProfileDictionary.Add(gmgProfile.Id, new CustomFieldValue + { + DisplayValue = existingGmgProfileItem!.Name, + Value = existingGmgProfileItem!.Guid.ToGeneralIdRef().ToJson() + }); + } + } + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/GmgProfile.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/GmgProfile.cs new file mode 100644 index 0000000..bef2bdc --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/GmgProfile.cs @@ -0,0 +1,9 @@ +namespace e_suite.Service.SigmaImporter.Repository; + +public class GmgProfile +{ + public long Id { get; set; } + public long Number { get; set; } + public string Name { get; set; } = string.Empty; + public string CompiledName => $"{Number}_{Name}"; +} diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/ISigmaFileBrowserRepository.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/ISigmaFileBrowserRepository.cs new file mode 100644 index 0000000..0295c90 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/ISigmaFileBrowserRepository.cs @@ -0,0 +1,6 @@ +namespace e_suite.Service.SigmaImporter.Repository; + +public interface ISigmaFileBrowserRepository +{ + Task> GetActiveGmgProfiles(); +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/ISigmaFtpuRepository.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/ISigmaFtpuRepository.cs new file mode 100644 index 0000000..fb8b552 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/ISigmaFtpuRepository.cs @@ -0,0 +1,8 @@ +namespace e_suite.Service.SigmaImporter.Repository; + +public interface ISigmaFtpuRepository +{ + Task> GetActivePrintSpecifications(); + Task> GetActivePrintProcesses(); + Task> GetActivePrintSpecificationDomains(); +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/MySqlRepositoryBase.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/MySqlRepositoryBase.cs new file mode 100644 index 0000000..cce5f62 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/MySqlRepositoryBase.cs @@ -0,0 +1,86 @@ +using e_suite.API.Common.extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using MySqlConnector; + +namespace e_suite.Service.SigmaImporter.Repository; + +public class MySqlRepositoryBase : IDisposable +{ + protected readonly ILogger Logger; + protected readonly string ConfigSection; + protected readonly IConfiguration Configuration; + + private MySqlConnection? _connection = null; + + protected MySqlConnection Connection + { + get + { + if (_connection == null) + { + var connectionString = BuildConnectionString(Configuration, ConfigSection); + _connection = new MySqlConnection(connectionString); + _connection.Open(); + } + return _connection; + } + } + + public string BuildConnectionString(IConfiguration configuration, string configSection) + { + var server = configuration.GetConfigValue($"{configSection}_SERVER", $"{configSection}:Server", ""); + var database = configuration.GetConfigValue($"{configSection}_DATABASE", $"{configSection}:Database", ""); + var userId = configuration.GetConfigValue($"{configSection}_USERID", $"{configSection}:UserID", ""); + var password = configuration.GetConfigValue($"{configSection}_PASSWORD", $"{configSection}:Password", ""); + + //var sb = new StringBuilder(); + //sb.Append("Compiling ConnectionString for "); + //sb.AppendLine(configSection); + //sb.Append("Server: "); + //sb.AppendLine(server); + //sb.Append("Database: "); + //sb.AppendLine(database); + //sb.Append("UserId: "); + //sb.AppendLine(userId); + //sb.Append("Password length: "); + //sb.AppendLine(password!.Length.ToString()); + + //_logger.LogInformation(sb.ToString()); + + var builder = new MySqlConnectionStringBuilder + { + Server = server, + Database = database, + UserID = userId, + Password = password + }; + + return builder.ToString(); + } + + protected MySqlRepositoryBase(IConfiguration configuration, ILogger logger, string configSection) + { + Configuration = configuration; + ConfigSection = configSection; + Logger = logger; + } + + + + public void Dispose() + { + GC.SuppressFinalize(this); + Close(); + } + + protected void Close() + { + if (_connection != null) + { + Connection.Close(); + _connection = null; + } + + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaAirlockRepository.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaAirlockRepository.cs new file mode 100644 index 0000000..8227117 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaAirlockRepository.cs @@ -0,0 +1,37 @@ +using Dapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.Service.SigmaImporter.Repository; + +public interface ISigmaAirlockRepository +{ + Task> GetActivePrintSpecifications(); +} + +public class SigmaTlaHostName +{ + public string Tla { get; set; } = string.Empty; + public string Hostname { get; set; } = string.Empty; +} + +public class SigmaAirlockRepository : MySqlRepositoryBase, ISigmaAirlockRepository +{ + public SigmaAirlockRepository(IConfiguration configuration, ILogger logger) : base(configuration, logger, "SigmaAirlock") + { + } + + public async Task> GetActivePrintSpecifications() + { + try + { + var result = await Connection.QueryAsync("select distinct\r\n tla as Tla,\r\n domain as Hostname\r\nfrom stage_client\r\nwhere tla != ''"); + return result; + } + finally + { + Close(); + } + } + +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaFileBrowserRepository.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaFileBrowserRepository.cs new file mode 100644 index 0000000..d46b0e0 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaFileBrowserRepository.cs @@ -0,0 +1,26 @@ +using Dapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.Service.SigmaImporter.Repository; + +public class SigmaFileBrowserRepository : MySqlRepositoryBase, ISigmaFileBrowserRepository +{ + public SigmaFileBrowserRepository(IConfiguration configuration, ILogger logger) : base(configuration, logger, "SigmaFileBrowser") + { + } + + public async Task> GetActiveGmgProfiles() + { + try + { + var result = await Connection.QueryAsync( + "SELECT DISTINCT\r\n profile_id as id,\r\n profile_name as name,\r\n profile_number as number\r\nFROM profile_info\r\nwhere active = 1"); + return result; + } + finally + { + Close(); + } + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaFtpuRepository.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaFtpuRepository.cs new file mode 100644 index 0000000..d2220fc --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaFtpuRepository.cs @@ -0,0 +1,59 @@ +using Dapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.Service.SigmaImporter.Repository; + +public class PrintSpecDomain +{ + public long PrintSpecId { get; set; } + public long ClientId { get; set; } +} + +public class SigmaFtpuRepository : MySqlRepositoryBase, ISigmaFtpuRepository +{ + public SigmaFtpuRepository(IConfiguration configuration, ILogger logger) : base(configuration, logger, "SigmaFTPU") + { + } + + public async Task> GetActivePrintSpecifications() + { + try + { + var result = await Connection.QueryAsync( + "select\r\n ps.psID as SigmaId,\r\n printer.pID as SiteId,\r\n printer.name as PrinterName,\r\n printer.address as PrinterAddress,\r\n printer.country as PrinterCountry,\r\n p.name as Process,\r\n ps.name as Name,\r\n ps.trap as Trap,\r\n ps.maxink as MaxInk,\r\n ps.mpl as Mpl,\r\n ps.mnl as Mnl,\r\n ps.mmil as Mmil,\r\n ps.mmif as Mmif,\r\n ps.mpf as Mpf,\r\n ps.mnf as Mnf,\r\n ps.mindot as Mindot,\r\n ps.maxdot as Maxdot,\r\n ps.BWR as Bwr,\r\n ps.minmag as MinMag,\r\n ps.sequence_c as SequenceC,\r\n ps.sequence_m as SequenceM,\r\n ps.sequence_y as SequenceY,\r\n ps.sequence_k as SequenceK,\r\n ps.colours as Colours,\r\n ps.gmgFK as GmgFk,\r\n ps.supplymethod as SupplyMethod,\r\n ps.print_process as PrintProcess,\r\n ps.tech_spec as TechSpec,\r\n ps.digital_supply as DigitalSupply,\r\n ps.barcode as Barcode,\r\n ps.substrate as Substrate,\r\n ps.notes as Notes\r\nfrom ps_printspec as ps\r\nleft join ps_process as p\r\n on p.pID = ps.pfk\r\n and p.active = 1\r\nleft join ps_printer as printer\r\n on printer.pID = p.pFK\r\n and printer.active = 1\r\nwhere ps.active = 1;"); + return result; + } + finally + { + Close(); + } + } + + public async Task> GetActivePrintProcesses() + { + try + { + var result = await Connection.QueryAsync("select distinct p.name\r\nfrom ps_process as p\r\nwhere p.active = 1"); + return result; + } + finally + { + Close(); + } + } + + public async Task> GetActivePrintSpecificationDomains() + { + try + { + var result = await Connection.QueryAsync( + "select\r\n PS.psID as PrintSpecId, S.cFK as ClientId\r\nfrom ps_sites S\r\ninner join ps_printer PR on PR.pID=S.pFK\r\ninner join ps_process PC on PC.pFK=PR.pID\r\ninner join ps_printspec PS on PS.pFK=PC.pID\r\nand S.cFK not in (\r\n select\r\n pe.clientFK as clientid\r\n from ps_exclusion as pe\r\n where pe.printspecFK = PS.psID\r\n)\r\norder by\r\n PS.psID,\r\n S.cFK"); + return result; + } + finally + { + Close(); + } + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaPrintSpecification.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaPrintSpecification.cs new file mode 100644 index 0000000..afc7896 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaPrintSpecification.cs @@ -0,0 +1,38 @@ +namespace e_suite.Service.SigmaImporter.Repository; + +public class SigmaPrintSpecification +{ + public long SigmaId {get; set; } + public long SiteId { get; set; } + public string PrinterName { get; set; } = string.Empty; + public string PrinterAddress { get; set; } = string.Empty; + public string PrinterCountry { get; set; } = string.Empty; + public string Process { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public double? Trap { get; set; } + public long? MaxInk { get; set; } + public double? Mpl { get; set; } + public double? Mnl { get; set; } + public double? Mmil { get; set; } + public double? Mpf { get; set; } + public double? Mnf { get; set; } + public double? Mmif { get; set; } + public double? Mindot { get; set; } + public double? Maxdot { get; set; } + public double? Bwr { get; set; } + public double? MinMag { get; set; } + public int SequenceC { get; set; } + public int SequenceM { get; set; } + public int SequenceY { get; set; } + public int SequenceK { get; set; } + public int Colours { get; set; } + public int GmgFk { get; set; } + public string SupplyMethod { get; set; } = string.Empty; + public string PrintProcess { get; set; } = string.Empty; + public string TechSpec{ get; set; } = string.Empty; + public string DigitalSupply { get; set; } = string.Empty; + public string Barcode { get; set; } = string.Empty; + public string Substrate { get; set; } = string.Empty; + public string Notes { get; set; } = string.Empty; + +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaRepository.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaRepository.cs new file mode 100644 index 0000000..4285e70 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Repository/SigmaRepository.cs @@ -0,0 +1,39 @@ +using Dapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace e_suite.Service.SigmaImporter.Repository; + +public interface ISigmaRepository +{ + Task> GetDomains(); +} + +public class SigmaRepository : MySqlRepositoryBase, ISigmaRepository +{ + public SigmaRepository(IConfiguration configuration, ILogger logger) : base(configuration, logger,"Sigma") + { + } + + public async Task> GetDomains() + { + try + { + var result = await Connection.QueryAsync( + "select\r\n c.company_id as Id,\r\n c.name as Name,\r\n c.tla as Tla\r\nfrom live_company as c\r\nINNER JOIN live_odin_servers as os\r\n ON os.odinID=c.odinserverFK\r\n and os.version >= 3\r\nwhere c.active = '1'\r\nand c.reports = '1'"); + return result; + } + finally + { + Close(); + } + } +} + +public class SigmaDomain +{ + public long Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Tla { get; set; } = string.Empty; + public string Hostname { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Resources/GeneralPrintSpecificationFormTemplateDefintion.txt b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Resources/GeneralPrintSpecificationFormTemplateDefintion.txt new file mode 100644 index 0000000..4b89d5d --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/Resources/GeneralPrintSpecificationFormTemplateDefintion.txt @@ -0,0 +1 @@ +
Sequence 

C

{Sequence C}

M

{Sequence M}

Y

{Sequence Y}

K

{Sequence K}

Colours

{Colours}

Min Pos Line

{Minimum Pos Line}

Min Neg Line

{Minimum Neg Line}

Min Multi Ink Line

{Minimum Multi Ink Line}

Min Pos Font

{Minimum Pos Font}

Min Neg Font

{Minimum Neg Font}

Min Multi Ink Font

{Minimum Multi Ink Font}

Min Dot

{Min Dot}

Max Dot

{Max Dot}

Trap

{Trap}

Max Ink

{Max Ink}

BWR

{BWR}

Min Mag

{Min Mag}

GMG Profile

{GMG Profile}

Digital Supply Method

{Digital Supply Method}

Print Process

{Print Process}

Tech Spec Comments

{Tech Spec Comments}

Print Process Comments

{Print Process Comments}

Digital Supply Comments

{Digital Supply Comments}

Barcode Comments

{Barcode Comments}

Substrate Comments

{Substrate Comments}

Domains

{Domain}

Notes

{Notes}

\ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/SigmaImporter.cs b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/SigmaImporter.cs new file mode 100644 index 0000000..797254e --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/SigmaImporter.cs @@ -0,0 +1,35 @@ +using e_suite.API.Common; +using e_suite.Database.Audit; +using e_suite.Service.SigmaImporter.GmgProfiles; +using e_suite.Service.SigmaImporter.PrintSpecifications; + +namespace e_suite.Service.SigmaImporter; + +public class SigmaImporter : ISigmaImporter +{ + private readonly IGmgProfileImporter _gmgProfileImporter; + private readonly IPrintSpecificationImporter _printSpecificationImporter; + + public SigmaImporter(IGmgProfileImporter gmgProfileImporter, IPrintSpecificationImporter printSpecificationImporter) + { + _gmgProfileImporter = gmgProfileImporter; + _printSpecificationImporter = printSpecificationImporter; + } + + private readonly AuditUserDetails _auditUserDetails = new() + { + Comment = "SigmaImporter Automated import", + UserDisplayName = "MessageProcessor" + }; + + public async Task ImportGMGProfiles() + { + await _gmgProfileImporter.DoGmgProfileImport(_auditUserDetails); + } + + public async Task ImportPrintSpecifications() + { + await _gmgProfileImporter.DoGmgProfileImport(_auditUserDetails); + await _printSpecificationImporter.DoPrintSpecificationImport(_auditUserDetails); + } +} \ No newline at end of file diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/e-suite - Backup.Service.SigmaImporter.csproj b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/e-suite - Backup.Service.SigmaImporter.csproj new file mode 100644 index 0000000..c33ae77 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/e-suite - Backup.Service.SigmaImporter.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + e_suite.Service.SigmaImporter + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.csproj b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.csproj new file mode 100644 index 0000000..b288522 --- /dev/null +++ b/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter/e-suite.Service.SigmaImporter.csproj @@ -0,0 +1,33 @@ + + + + net10.0 + e_suite.Service.SigmaImporter + enable + enable + + + + + + + + + Always + Always + true + true + + + + + + + + + + + + + + diff --git a/e-suite.Service.SigmaImporter/nuget.config b/e-suite.Service.SigmaImporter/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Service.SigmaImporter/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.UnitTest.Core/.gitattributes b/e-suite.UnitTest.Core/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.UnitTest.Core/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.UnitTest.Core/.gitignore b/e-suite.UnitTest.Core/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.UnitTest.Core/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.UnitTest.Core/.runsettings b/e-suite.UnitTest.Core/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.UnitTest.Core/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.UnitTest.Core/README.md b/e-suite.UnitTest.Core/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.UnitTest.Core/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.UnitTest.Core/azure-pipelines.yml b/e-suite.UnitTest.Core/azure-pipelines.yml new file mode 100644 index 0000000..b4c9a0d --- /dev/null +++ b/e-suite.UnitTest.Core/azure-pipelines.yml @@ -0,0 +1,137 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.UnitTestCore/e-suite.UnitTestCore.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +#- task: VSTest@2 +# displayName: 'Run Tests' +# inputs: +# testAssemblyVer2: | +# **\*Tests.dll +# !**\obj\** +# runOnlyImpactedTests: false +# runInParallel: true +# codeCoverageEnabled: true +# runSettingsFile: .runsettings +# platform: '$(BuildPlatform)' +# configuration: '$(BuildConfiguration)' + +#This build step is commented out as there is no distrubuted code in this solution. It contains code that is used to help make the other packages +#- task: BuildQualityChecks@9 +# displayName: 'Check build quality' +# inputs: +# # ===== Warnings Policy Inputs ===== +# checkWarnings: true # Optional +# warningFailOption: fixed # Optional; Valid values: build, fixed +# warningThreshold: '0' # Optional +# #forceFewerWarnings: false # Optional +# #allowWarningVariance: false # Optional +# #warningVariance: # Required if allowWarningVariance = true +# #showStatistics: false # Optional +# #evaluateTaskWarnings: true # Optional +# #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) +# #warningSelectors: # Optional (alias: warningFilters) +# #inclusiveSelection: false # Optional (alias: inclusiveFiltering) +# #evaluateFileWarnings: false # Optional +# #warningFilesFolder: # Optional +# #warningFiles: # Required if evaluateFileWarnings = true +# #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) +# #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) +# # ===== Code Coverage Policy Inputs ===== +# checkCoverage: true # Optional +# coverageFailOption: fixed # Optional; Valid values: build, fixed +# coverageType: lines # Optional; Valid values: blocks, lines, branches, custom +# #customCoverageType: # Required if coverageType = custom +# #treat0of0as100: false # Optional +# coverageThreshold: '80' # Optional +# forceCoverageImprovement: true # Optional +# #coverageUpperThreshold: '80' # Optional +# #ignoreDecreaseAboveUpperThreshold: true # Optional +# #useUncoveredElements: false # Optional +# #allowCoverageVariance: false # Optional +# #coverageVariance: # Required if allowCoverageVariance = true +# #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage +# #coveragePrecision: '4' # Optional +# #buildConfiguration: # Optional +# #buildPlatform: # Optional +# #explicitSelector: false # Optional (alias: explicitFilter) +# # ===== Baseline Inputs ===== +# #includePartiallySucceeded: true # Optional +# #fallbackOnPRTargetBranch: true # Optional +# #baseDefinitionSelector: # Ignored - only used by UI editor +# #baseDefinitionId: # Optional +# #baseRepoId: # Ignored - only used by UI editor +# #baseBranchRef: # Optional +# # ===== Reporting Inputs ===== +# #runTitle: # Optional +# #fileAnalysisTitle: # Optional +# # ===== Advanced Inputs ===== +# #disableCertCheck: false # Optional +# #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore.sln b/e-suite.UnitTest.Core/e-suite.UnitTestCore.sln new file mode 100644 index 0000000..e1385f4 --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.UnitTestCore", "e-suite.UnitTestCore\e-suite.UnitTestCore.csproj", "{6946BCDE-8F67-415C-9017-2C38B8DE7328}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6946BCDE-8F67-415C-9017-2C38B8DE7328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6946BCDE-8F67-415C-9017-2C38B8DE7328}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6946BCDE-8F67-415C-9017-2C38B8DE7328}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6946BCDE-8F67-415C-9017-2C38B8DE7328}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C96AB857-8136-478A-9F75-D9F524967C4E} + EndGlobalSection +EndGlobal diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore/AutomationTestBase.cs b/e-suite.UnitTest.Core/e-suite.UnitTestCore/AutomationTestBase.cs new file mode 100644 index 0000000..7043364 --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore/AutomationTestBase.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Text.Json; + +namespace e_suite.UnitTestCore; + +public class AutomationTestBase +{ + protected TestEnvironment TestEnvironment { get; } + + public AutomationTestBase() + { + var executingAssembly = Assembly.GetCallingAssembly(); + var assemblyConfigurationAttribute = executingAssembly.GetCustomAttribute(); + var buildConfigurationName = assemblyConfigurationAttribute?.Configuration; + + var fileName = $"config.{buildConfigurationName}.json"; + string jsonString = File.ReadAllText(fileName); + TestEnvironment = JsonSerializer.Deserialize(jsonString)!; + } +} \ No newline at end of file diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore/FakeClock.cs b/e-suite.UnitTest.Core/e-suite.UnitTestCore/FakeClock.cs new file mode 100644 index 0000000..27485e4 --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore/FakeClock.cs @@ -0,0 +1,16 @@ +using eSuite.Core.Clock; + +namespace e_suite.UnitTestCore; + +public class FakeClock : IClock +{ + /// + /// You can set the date and time using this property. + /// + public DateTimeOffset DateTime { get; set; } = DateTimeOffset.UtcNow; + + /// + /// The application will user this to get the current date and time. + /// + public DateTimeOffset GetNow => DateTime; +} \ No newline at end of file diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore/FakeRepository.cs b/e-suite.UnitTest.Core/e-suite.UnitTestCore/FakeRepository.cs new file mode 100644 index 0000000..96f6785 --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore/FakeRepository.cs @@ -0,0 +1,32 @@ +using e_suite.Database.Core; +using Microsoft.EntityFrameworkCore; +using Moq; + +namespace e_suite.UnitTestCore; + +public class FakeRepository : IRepository +{ + public async Task TransactionAsync(Func> action) + { + return await action(); + } + + public async Task TransactionAsync(Func action) + { + await action(); + } + + protected static DbSet GetQueryableMockDbSet(List sourceList) where T : class + { + var queryable = sourceList.AsQueryable(); + + var dbSet = new Mock>(); + dbSet.As>().Setup(m => m.Provider).Returns(queryable.Provider); + dbSet.As>().Setup(m => m.Expression).Returns(queryable.Expression); + dbSet.As>().Setup(m => m.ElementType).Returns(queryable.ElementType); + dbSet.As>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); + dbSet.Setup(d => d.Add(It.IsAny())).Callback((s) => sourceList.Add(s)); + + return dbSet.Object; + } +} \ No newline at end of file diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore/TestBase.cs b/e-suite.UnitTest.Core/e-suite.UnitTestCore/TestBase.cs new file mode 100644 index 0000000..5bca0f6 --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore/TestBase.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.Configuration; + +namespace e_suite.UnitTestCore; + +public class TestBase +{ + protected IConfiguration _configuration = null!; + protected FakeClock _fakeClock = null!; + + public virtual Task Setup() + { + var appSettingsStub = new Dictionary { + {"applicationName", "e-suite test"}, + {"baseUrl", "https://esuite.test"}, + {"Smtp:EmailTimeoutHours", "48"}, + {"Smtp:Server", "127.0.0.1"}, + {"Smtp:Port", "25"}, + {"Smtp:FromAddress", "esuitetest@sun-strategy.com"}, + {"JwtConfig:secret", "Z8p9YKvYnwm62sPLJVdvp3M7bQ5l0UqRGwz95ZqL"}, + {"JwtConfig:expirationInMinutes", "15"}, + {"JwtConfig:audience", "test"}, + {"JwtConfig:issuer", "moq"}, + {"Sentinel:LoginAttemptTimeoutMinutes", "60"}, + {"Sentinel:MaxLoginAttempts", "5"} + }; + + _configuration = new ConfigurationBuilder() + .AddInMemoryCollection(appSettingsStub!) + .Build(); + + _fakeClock = new FakeClock(); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore/TestEnvironment.cs b/e-suite.UnitTest.Core/e-suite.UnitTestCore/TestEnvironment.cs new file mode 100644 index 0000000..2df65ea --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore/TestEnvironment.cs @@ -0,0 +1,43 @@ +namespace e_suite.UnitTestCore; + +public class TestEnvironment +{ + private string _baseUrl = string.Empty; + + public string BaseUrl + { + get => _baseUrl; + set => _baseUrl = value.TrimEnd('/'); + } + + private string _apiUrl = string.Empty; + public string APIUrl + { + get => _apiUrl; + set => _apiUrl = value.TrimEnd('/'); + } + + public int ClickWaitSeconds { get; set; } = 60; + + public int DebounceDelayMilliseconds { get; set; } = 2500; + + public TimeSpan ClickWaitTime => TimeSpan.FromSeconds(ClickWaitSeconds); + + public string Username { get; set; } = "testuser1@sun-strategy.com"; + + public string Password { get; set; } = "12345 Same as my luggage"; + + public bool HeadlessMode { get; set; } = true; + + private string _testMailAppAPIKey = string.Empty; + public string TestMailAppAPIKey { + get => _testMailAppAPIKey; + set => _testMailAppAPIKey = value; + } + + private string _testMailAppNamespace = string.Empty; + public string TestMailAppNamespace { + get => _testMailAppNamespace; + set => _testMailAppNamespace = value; + } +} \ No newline at end of file diff --git a/e-suite.UnitTest.Core/e-suite.UnitTestCore/e-suite.UnitTestCore.csproj b/e-suite.UnitTest.Core/e-suite.UnitTestCore/e-suite.UnitTestCore.csproj new file mode 100644 index 0000000..a979b63 --- /dev/null +++ b/e-suite.UnitTest.Core/e-suite.UnitTestCore/e-suite.UnitTestCore.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + e_suite.UnitTestCore + enable + enable + + + + + + + + + + + + diff --git a/e-suite.UnitTest.Core/nuget.config b/e-suite.UnitTest.Core/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.UnitTest.Core/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/.gitattributes b/e-suite.Utilities.Pagination/.gitattributes new file mode 100644 index 0000000..d7c444c --- /dev/null +++ b/e-suite.Utilities.Pagination/.gitattributes @@ -0,0 +1 @@ +* -crlf \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/.gitignore b/e-suite.Utilities.Pagination/.gitignore new file mode 100644 index 0000000..fa03bff --- /dev/null +++ b/e-suite.Utilities.Pagination/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# New VS2015 folders +.vs/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# 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/ + +# NuGet Packages Directory +packages/ + +# Compare files +*.orig + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.pfx +*.publishsettings +*.swp + +# 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 + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + +# TeX files +Documentation/*.aux +Documentation/*.out +Documentation/*.pdf +Documentation/*.idx +Documentation/*.toc +Documentation/*.gz + +# image resizer cache +imagecache/ +*.DotSettings + +# TypeScript mapping files +*.js.map + +# Exclude all Typescript-generated JS files +src/Sunrise.Web.Customer/App/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/App/**/*.js +src/Sunrise.Web.Customer/Views/**/*.js +src/Sunrise.Web.Customer/Areas/**/*.js +src/Sunrise.Web.Support/Views/**/*.js + +*.GhostDoc.user.dic +*.GhostDoc.xml + +/TestResult.xml +*.VisualState.xml + +artifacts/ +/src/Sunrise.Web.Customer/Scripts/typings + +# Db project +src/Sunrise.Database/*.jfm +src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Database/*.jfm +/src/Sunrise.Database/Sunrise.Database.jfm +/src/Sunrise.Web.Customer/node_modules + +# node modules +node_modules +.eslintrc + +#NCrunch folders +_NCrunch*/ +src/Sunrise.Web.FrontEnd/.eslintrc.js +src/Sunrise.Web.FrontEnd/.prettierrc +src/Sunrise.Web.FrontEnd/.vscode/settings.json +src/Sunrise.Web.Customer/Content/bundles/vendor.js diff --git a/e-suite.Utilities.Pagination/.runsettings b/e-suite.Utilities.Pagination/.runsettings new file mode 100644 index 0000000..07b5799 --- /dev/null +++ b/e-suite.Utilities.Pagination/.runsettings @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + .*\.dll$ + .*\.exe$ + + + .*moq.dll + .*nunit3.testadapter.dll + + + + C:\b59fb11c-1611-4562-9a2b-c35719da65d3 + + + + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + + \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/README.md b/e-suite.Utilities.Pagination/README.md new file mode 100644 index 0000000..0ca446a --- /dev/null +++ b/e-suite.Utilities.Pagination/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/azure-pipelines.yml b/e-suite.Utilities.Pagination/azure-pipelines.yml new file mode 100644 index 0000000..1b6d952 --- /dev/null +++ b/e-suite.Utilities.Pagination/azure-pipelines.yml @@ -0,0 +1,136 @@ +# ASP.NET Core (.NET Framework) +# Build and test ASP.NET Core projects targeting the full .NET Framework. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core + +#name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(prerelease) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + nugetProject: 'e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.csproj' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + prerelease: '' + ${{ elseif eq(variables['Build.SourceBranchName'], 'develop') }}: + prerelease: '-beta' + ${{ else }}: + prerelease: '-alpha' + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Nuget' + +- task: NuGetCommand@2 + displayName: 'Nuget Restore' + inputs: + restoreSolution: '$(solution)' + feedsToUse: config + includeNuGetOrg: true + packagesdirectory: '..\packages' + +- task: VSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + displayName: 'Run Tests' + inputs: + testAssemblyVer2: | + **\*Tests.dll + !**\obj\** + runOnlyImpactedTests: false + runInParallel: true + codeCoverageEnabled: true + runSettingsFile: .runsettings + platform: '$(BuildPlatform)' + configuration: '$(BuildConfiguration)' + +- task: BuildQualityChecks@9 + displayName: 'Check build quality' + inputs: + # ===== Warnings Policy Inputs ===== + checkWarnings: true # Optional + warningFailOption: fixed # Optional; Valid values: build, fixed + warningThreshold: '0' # Optional + #forceFewerWarnings: false # Optional + #allowWarningVariance: false # Optional + #warningVariance: # Required if allowWarningVariance = true + #showStatistics: false # Optional + #evaluateTaskWarnings: true # Optional + #warningTaskSelectors: '/^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$/i' # Optional (alias: warningTaskFilters) + #warningSelectors: # Optional (alias: warningFilters) + #inclusiveSelection: false # Optional (alias: inclusiveFiltering) + #evaluateFileWarnings: false # Optional + #warningFilesFolder: # Optional + #warningFiles: # Required if evaluateFileWarnings = true + #fileWarningSelectors: # Required if evaluateFileWarnings = true (alias: warningFileFilters) + #warningFilesArtifact: # Required if evaluateFileWarnings = true and (warningFailOption = build or showStatistics = true) + # ===== Code Coverage Policy Inputs ===== + checkCoverage: true # Optional + coverageFailOption: fixed # Optional; Valid values: build, fixed + coverageType: lines # Optional; Valid values: blocks, lines, branches, custom + #customCoverageType: # Required if coverageType = custom + #treat0of0as100: false # Optional + coverageThreshold: '80' # Optional + forceCoverageImprovement: true # Optional + #coverageUpperThreshold: '80' # Optional + #ignoreDecreaseAboveUpperThreshold: true # Optional + #useUncoveredElements: false # Optional + #allowCoverageVariance: false # Optional + #coverageVariance: # Required if allowCoverageVariance = true + #coverageDeltaType: percentage # Optional; Valid values: absolute, percentage + #coveragePrecision: '4' # Optional + #buildConfiguration: # Optional + #buildPlatform: # Optional + #explicitSelector: false # Optional (alias: explicitFilter) + # ===== Baseline Inputs ===== + #includePartiallySucceeded: true # Optional + #fallbackOnPRTargetBranch: true # Optional + #baseDefinitionSelector: # Ignored - only used by UI editor + #baseDefinitionId: # Optional + #baseRepoId: # Ignored - only used by UI editor + #baseBranchRef: # Optional + # ===== Reporting Inputs ===== + #runTitle: # Optional + #fileAnalysisTitle: # Optional + # ===== Advanced Inputs ===== + #disableCertCheck: false # Optional + #createBuildIssues: true # Optional + +- task: DotNetCoreCLI@2 + displayName: "Package Nuget Artifact" + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'pack' + arguments: '--configuration $(buildConfiguration)' + packagesToPack: '$(nugetProject)' + nobuild: true + versionEnvVar: 'build.BuildNumber' + versioningScheme: 'byEnvVar' + #versioningScheme: byBuildNumber # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet + +- task: NuGetCommand@2 + displayName: 'Publish Nuget Artifact' + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + command: 'push' + feedsToUse: 'select' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: 'e-suite/e-suite' + versioningScheme: 'off' + allowPackageConflicts: true \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.UnitTests/PaginateUnitTests.cs b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.UnitTests/PaginateUnitTests.cs new file mode 100644 index 0000000..a3b5d0d --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.UnitTests/PaginateUnitTests.cs @@ -0,0 +1,419 @@ +using System.Linq.Expressions; +using MockQueryable; +using NUnit.Framework; + +namespace e_suite.Utilities.Pagination.UnitTests; + +public class TestData +{ + public string Name = string.Empty; + public long Id; +} + +[TestFixture] +public class PaginateUnitTests +{ + private Expression> FilterSelector(string key, string value) + { + return key.ToLowerInvariant() switch + { + "id" => x => x.Id.ToString().Contains(value), + _ => x => x.Name.Contains(value) + }; + } + + private Expression> KeySelector(string sortKey) + { + return sortKey.ToLowerInvariant() switch + { + "id" => x => x.Id, + _ => x => x.Name + }; + } + + [Test] + public async Task Paginate_WhenNoSpecialValues_ReturnsExpectedResults() + { + var data = new List + { + new() {Id =1, Name = "test1"} + }; + + var queryable = data.BuildMock(); + + var paging = new Paging(); + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(1)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Paginate_TenItems_ReturnsTenItems() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging(); + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(10)); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(1)); + Assert.That(result.Data.Count, Is.EqualTo(10)); + } + + [Test] + public async Task Paginate_ElevenItems_ReturnsPageOne() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + var paging = new Paging(); + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(2)); + Assert.That(result.Data.Count, Is.EqualTo(10)); + } + + [Test] + public async Task Paginate_Page2Requested_ReturnsPageTwo() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Page = 2 + }; + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(2)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(2)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Paginate_SortAscendingTrueAndPage2_ReturnsExpectedData() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Page = 2 + }; + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(2)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(2)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + + var checkItem = result.Data.Single(); + + Assert.That(checkItem.Id, Is.EqualTo(9)); + Assert.That(checkItem.Name, Is.EqualTo("test9")); + } + + [Test] + public async Task Paginate_SortAscendingFalseAndPage2_ReturnsExpectedData() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Page = 2, + SortAscending = false + }; + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(2)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(2)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + + var checkItem = result.Data.Single(); + + Assert.That(checkItem.Id, Is.EqualTo(1)); + Assert.That(checkItem.Name, Is.EqualTo("test1")); + } + + [Test] + public async Task Paginate_SortAscendingFalseByIdAndPage2_ReturnsExpectedData() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Page = 2, + SortKey = "id", + SortAscending = false, + }; + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(2)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(2)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + + var checkItem = result.Data.Single(); + + Assert.That(checkItem.Id, Is.EqualTo(1)); + Assert.That(checkItem.Name, Is.EqualTo("test1")); + } + + [Test] + public async Task Paginate_SortAscendingTrueByIdAndPage2_ReturnsExpectedData() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Page = 2, + SortKey = "id", + SortAscending = true, + }; + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(2)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(2)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + + var checkItem = result.Data.Single(); + + Assert.That(checkItem.Id, Is.EqualTo(11)); + Assert.That(checkItem.Name, Is.EqualTo("test11")); + } + + [Test] + public async Task Paginate_SearchFilterContainsId_ReturnsExpectedData() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Filters = "{\"id\":\"2\"}" + }; + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(1)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + + var checkItem = result.Data.Single(); + + Assert.That(checkItem.Id, Is.EqualTo(2)); + Assert.That(checkItem.Name, Is.EqualTo("test2")); + } + + [Test] + public async Task Paginate_SearchFilterContainsName_ReturnsExpectedData() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Filters = "{\"name\":\"test2\"}" + }; + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(10)); + Assert.That(result.TotalPages, Is.EqualTo(1)); + Assert.That(result.Data.Count, Is.EqualTo(1)); + + var checkItem = result.Data.Single(); + + Assert.That(checkItem.Id, Is.EqualTo(2)); + Assert.That(checkItem.Name, Is.EqualTo("test2")); + } + + + [Test] + public async Task Paginate_RequestingPage0_ReturnsEveryRow() + { + var data = new List + { + new() { Id = 1, Name = "test1" }, + new() { Id = 2, Name = "test2" }, + new() { Id = 3, Name = "test3" }, + new() { Id = 4, Name = "test4" }, + new() { Id = 5, Name = "test5" }, + new() { Id = 6, Name = "test6" }, + new() { Id = 7, Name = "test7" }, + new() { Id = 8, Name = "test8" }, + new() { Id = 9, Name = "test9" }, + new() { Id = 10, Name = "test10" }, + new() { Id = 11, Name = "test11" } + }; + + var queryable = data.BuildMock(); + + var paging = new Paging + { + Page = 0, + PageSize = 5 + }; + + var result = await PaginatedData.Paginate(queryable, paging, KeySelector, FilterSelector, CancellationToken.None); + + Assert.That(result.Count, Is.EqualTo(11)); + Assert.That(result.Page, Is.EqualTo(1)); + Assert.That(result.PageSize, Is.EqualTo(5)); + Assert.That(result.TotalPages, Is.EqualTo(3)); + Assert.That(result.Data.Count, Is.EqualTo(11)); + } +} \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.UnitTests/e-suite.Utilities.Pagination.UnitTests.csproj b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.UnitTests/e-suite.Utilities.Pagination.UnitTests.csproj new file mode 100644 index 0000000..b3ca75e --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.UnitTests/e-suite.Utilities.Pagination.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + e_suite.Utilities.Pagination.UnitTests + enable + enable + + + + + + + + + + + + + + + diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.sln b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.sln new file mode 100644 index 0000000..cad0e0b --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33205.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Utilities.Pagination", "e-suite.Utilities.Pagination\e-suite.Utilities.Pagination.csproj", "{AEB7847B-3A4A-42FF-8472-2E1D9A3EE80E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{F36E4AC7-E464-471F-9BE1-D75E5D953602}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{A8BAA1C6-5A26-47C5-AA63-A770482E90B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Utilities.Pagination.UnitTests", "e-suite.Utilities.Pagination.UnitTests\e-suite.Utilities.Pagination.UnitTests.csproj", "{5F6BBC3B-570D-463A-B03E-40A7DF9CD5B8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AEB7847B-3A4A-42FF-8472-2E1D9A3EE80E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEB7847B-3A4A-42FF-8472-2E1D9A3EE80E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEB7847B-3A4A-42FF-8472-2E1D9A3EE80E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEB7847B-3A4A-42FF-8472-2E1D9A3EE80E}.Release|Any CPU.Build.0 = Release|Any CPU + {5F6BBC3B-570D-463A-B03E-40A7DF9CD5B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F6BBC3B-570D-463A-B03E-40A7DF9CD5B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F6BBC3B-570D-463A-B03E-40A7DF9CD5B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F6BBC3B-570D-463A-B03E-40A7DF9CD5B8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A8BAA1C6-5A26-47C5-AA63-A770482E90B7} = {F36E4AC7-E464-471F-9BE1-D75E5D953602} + {5F6BBC3B-570D-463A-B03E-40A7DF9CD5B8} = {A8BAA1C6-5A26-47C5-AA63-A770482E90B7} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E9B45D1F-579A-481F-9D57-EB58AB0CD125} + EndGlobalSection +EndGlobal diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/IPaginatedData.cs b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/IPaginatedData.cs new file mode 100644 index 0000000..c8ff039 --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/IPaginatedData.cs @@ -0,0 +1,10 @@ +namespace e_suite.Utilities.Pagination; + +public interface IPaginatedData +{ + long Count { get; } + int PageSize { get; } + int Page { get; } + int TotalPages { get; } + IEnumerable Data { get; } +} \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/PaginatedData.cs b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/PaginatedData.cs new file mode 100644 index 0000000..54fcecd --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/PaginatedData.cs @@ -0,0 +1,69 @@ +using System.Linq.Expressions; +using System.Text.Json; +using Microsoft.EntityFrameworkCore; + +namespace e_suite.Utilities.Pagination; + +public class PaginatedData : IPaginatedData +{ + public long Count { get; set; } + public int PageSize { get; set; } + public int Page { get; set; } + public int TotalPages => Convert.ToInt32(Math.Ceiling(Count / Convert.ToDecimal(PageSize))); + public IEnumerable Data { get; set; } = null!; +} + +public static class PaginatedData +{ + public static async Task> Paginate(IQueryable queryable, Paging paging, Func>> keySelector, + Func>> filterSelector, CancellationToken cancellationToken) + { + var filteredData = ApplyFilters(queryable, paging.Filters, filterSelector); + + var paginated = new PaginatedData + { + Count = await filteredData.CountAsync(cancellationToken), + Page = paging.Page, + PageSize = paging.PageSize + }; + + if (paginated.Page > paginated.TotalPages) paginated.Page = paginated.TotalPages; + if (paginated.Page < 1) paginated.Page = 1; + + var sortedData = ApplySort(filteredData, paging.SortKey, paging.SortAscending, keySelector); + paginated.Data = paging.Page == 0 ? sortedData : sortedData.Skip((paginated.Page - 1) * paginated.PageSize).Take(paginated.PageSize); + return paginated; + } + + private static IQueryable ApplyFilters(IQueryable queryable, string filters, + Func>> filterSelector) + { + if (string.IsNullOrWhiteSpace(filters)) + return queryable; + + var filtersDictionary = JsonSerializer.Deserialize>(filters); + + if (filtersDictionary == null) + return queryable; + + var filteredQueryable = queryable; + + foreach (var filter in filtersDictionary) + { + if (!string.IsNullOrWhiteSpace(filter.Value)) + { + filteredQueryable = filteredQueryable.Where(filterSelector(filter.Key, filter.Value)); + } + } + + return filteredQueryable; + } + + private static IQueryable ApplySort(IQueryable sequences, string sortKey, bool sortAscending, + Func>> keySelector) + { + if (sortAscending) + return sequences.OrderBy(keySelector(sortKey)); + return sequences.OrderByDescending(keySelector(sortKey)); + } +} \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/Paging.cs b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/Paging.cs new file mode 100644 index 0000000..ef1f10b --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/Paging.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace e_suite.Utilities.Pagination; + +public class Paging +{ + [DefaultValue(1)] + public int Page { get; set; } = 1; + + [DefaultValue(10)] + public int PageSize { get; set; } = 10; + + [DefaultValue("")] + public string SortKey { get; set; } = ""; + + [DefaultValue(true)] + public bool SortAscending { get; set; } = true; + + [DefaultValue("{}")] + public string Filters { get; set; } = "{}"; +} \ No newline at end of file diff --git a/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.csproj b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.csproj new file mode 100644 index 0000000..4e0d680 --- /dev/null +++ b/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination/e-suite.Utilities.Pagination.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + e_suite.Utilities.Pagination + enable + enable + + + + + + + diff --git a/e-suite.Utilities.Pagination/nuget.config b/e-suite.Utilities.Pagination/nuget.config new file mode 100644 index 0000000..e86847e --- /dev/null +++ b/e-suite.Utilities.Pagination/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.WorkBench/.gitignore b/e-suite.WorkBench/.gitignore new file mode 100644 index 0000000..1ee5385 --- /dev/null +++ b/e-suite.WorkBench/.gitignore @@ -0,0 +1,362 @@ +## 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 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# CodeRush personal settings +.cr/personal + +# 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/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd diff --git a/e-suite.WorkBench/README.md b/e-suite.WorkBench/README.md new file mode 100644 index 0000000..e37e4b1 --- /dev/null +++ b/e-suite.WorkBench/README.md @@ -0,0 +1,20 @@ +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) +- [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file diff --git a/e-suite.WorkBench/azure-pipelines.yml b/e-suite.WorkBench/azure-pipelines.yml new file mode 100644 index 0000000..301a885 --- /dev/null +++ b/e-suite.WorkBench/azure-pipelines.yml @@ -0,0 +1,128 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)$(postfix)$(branchName) # NOTE: rev resets when the default retention period expires + +trigger: + branches: + include: + - '*' + +pool: + vmImage: windows-latest # ubuntu-latest - set to windows-latest or another Windows vmImage for Windows builds + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + + ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: + branchName: '' + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}: + branchName: $[ replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-' ) ] + ${{ elseif startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}: + branchName: $[ replace(replace(variables['System.PullRequest.TargetBranch'], 'refs/heads/', ''), '/', '-' ) ] + + ${{ if eq(variables['branchName'], '') }}: + postfix: '' + ${{ else }}: + postfix: '-' + +steps: +- task: UseDotNet@2 + displayName: 'Set .net core version' + inputs: + version: '6.0.x' + +- task: PowerShell@2 + displayName: 'Update Build Version Number' + inputs: + targetType: 'inline' + script: | + $VersionRegex = "\d+\.\d+\.\d+\.\d+" + $VersionData = [string]::Format("{0}",[regex]::matches($Env:BUILD_BUILDNUMBER,$VersionRegex)[0]).substring(2) + + Write-Host "Versioning started" + "Sources directory " + $Env:BUILD_SOURCESDIRECTORY + "Build number " + $VersionData + $csprojfilename = $Env:BUILD_SOURCESDIRECTORY+"\eSuite.WorkBench\eSuite.WorkBench.csproj" + "Project file to update " + $csprojfilename + [xml]$csprojcontents = Get-Content -Path $csprojfilename; + "Current version number is " + $csprojcontents.Project.PropertyGroup.Version + $oldversionNumber = $csprojcontents.Project.PropertyGroup.Version + $csprojcontents.Project.PropertyGroup.Version = $VersionData + $csprojcontents.Save($csprojfilename) + "Version number has been udated from " + $oldversionNumber + " to " + $VersionData + Write-Host "Finished" + +- task: DotNetCoreCLI@2 + displayName: 'Nuget Restore' + inputs: + command: 'restore' + feedsToUse: config + projects: '**/*.csproj' + nugetConfigPath: nuget.config + +- task: VSBuild@1 + displayName: 'Build' + inputs: + solution: '$(solution)' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + msbuildArgs: '/p:RunWixToolsOutOfProc=true' + + +- task: CopyFiles@2 + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + sourceFolder: eSuite.WorkBench.Installer\bin\$(buildConfiguration) + contents: eSuite.WorkBench.Installer.msi + targetFolder: $(build.artifactstagingdirectory) + #cleanTargetFolder: false # Optional + #overWrite: false # Optional + #flattenFolders: false # Optional + #preserveTimestamp: false # Optional + #retryCount: 0 # Optional + #ignoreMakeDirErrors: false # Optional + +- task: PublishBuildArtifacts@1 + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + #pathToPublish: '$(Build.ArtifactStagingDirectory)' + artifactName: 'installer' + #publishLocation: 'Container' # Options: container, filePath + #targetPath: # Required when publishLocation == FilePath + #parallel: false # Optional + #parallelCount: # Optional + #fileCopyOptions: #Optional + #storeAsTar: false # Optional + +#Disabling this as the universal packages are not straight forward to work with. +#- task: UniversalPackages@0 +# displayName: 'Publish To artifacts feed' +# inputs: +# command: 'publish' # Options: download, publish +# #downloadDirectory: '$(System.DefaultWorkingDirectory)' # Required when command == Download +# feedsToUse: 'internal' # Options: internal, external +# #externalFeedCredentials: # Optional +# vstsFeed: 'e-suite/e-suite' # Required when feedsToUse == Internal +# #vstsFeedPackage: # Required when feedsToUse == Internal +# #vstsPackageVersion: # Required when feedsToUse == Internal +# #feedDownloadExternal: # Required when feedsToUse == External +# #packageDownloadExternal: # Required when feedsToUse == External +# #versionDownloadExternal: # Required when feedsToUse == External +# publishDirectory: '$(Build.ArtifactStagingDirectory)' # Required when command == Publish +# feedsToUsePublish: 'internal' # Options: internal, external +# #publishFeedCredentials: # Required when feedsToUsePublish == External +# vstsFeedPublish: 'e-suite/e-suite'# Required when feedsToUsePublish == Internal +# #publishPackageMetadata: true # Optional +# vstsFeedPackagePublish: 'e-suite.workbench' # Required when feedsToUsePublish == Internal +# #feedPublishExternal: # Required when feedsToUsePublish == External +# #packagePublishExternal: # Required when feedsToUsePublish == External +# #versionOption: 'patch' # Options: major, minor, patch, custom +# #versionPublish: # Required when versionOption == Custom +# packagePublishDescription: 'Easily choose and run your e-suite locally' +# #verbosity: 'None' # Options: none, trace, debug, information, warning, error, critical +# #publishedPackageVar: # Optional \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/Config.wxi b/e-suite.WorkBench/eSuite.WorkBench.Installer/Config.wxi new file mode 100644 index 0000000..03c7162 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/Config.wxi @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/Directories.wxs b/e-suite.WorkBench/eSuite.WorkBench.Installer/Directories.wxs new file mode 100644 index 0000000..e68106c --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/Directories.wxs @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/FeatureTree.wxs b/e-suite.WorkBench/eSuite.WorkBench.Installer/FeatureTree.wxs new file mode 100644 index 0000000..8dfd900 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/FeatureTree.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/InstallationUI.wxs b/e-suite.WorkBench/eSuite.WorkBench.Installer/InstallationUI.wxs new file mode 100644 index 0000000..a513c14 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/InstallationUI.wxs @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + "1"]]> + + 1 + + NOT Installed + Installed AND PATCH + + + + + + NOT Installed + Installed AND NOT PATCH + Installed AND PATCH + + 1 + + 1 + 1 + 1 + + + + + + + diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/Product.wxs b/e-suite.WorkBench/eSuite.WorkBench.Installer/Product.wxs new file mode 100644 index 0000000..c48863c --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/Product.wxs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/e-Suite_Logo_NoText.ico b/e-suite.WorkBench/eSuite.WorkBench.Installer/e-Suite_Logo_NoText.ico new file mode 100644 index 0000000..0c0e634 Binary files /dev/null and b/e-suite.WorkBench/eSuite.WorkBench.Installer/e-Suite_Logo_NoText.ico differ diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/eSuite.WorkBench.Installer.wixproj b/e-suite.WorkBench/eSuite.WorkBench.Installer/eSuite.WorkBench.Installer.wixproj new file mode 100644 index 0000000..c6d5e41 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/eSuite.WorkBench.Installer.wixproj @@ -0,0 +1,66 @@ + + + + Debug + x86 + 3.10 + 6aaf4506-6842-4012-9d61-8336719ad0aa + 2.0 + eSuite.WorkBench.Installer + Package + + + bin\$(Configuration)\ + obj\$(Configuration)\ + Debug + 91; + + + bin\$(Configuration)\ + obj\$(Configuration)\ + + + + + + + + + + + + + + + eSuite.WorkBench + {e6d4e7c8-e5c3-4f16-acde-f07e2c12db93} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + $(WixExtDir)\WixNetFxExtension.dll + WixNetFxExtension + + + + + + + + + \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench.Installer/eSuiteWorkbench.wxs b/e-suite.WorkBench/eSuite.WorkBench.Installer/eSuiteWorkbench.wxs new file mode 100644 index 0000000..6350674 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.Installer/eSuiteWorkbench.wxs @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/e-suite.WorkBench/eSuite.WorkBench.sln b/e-suite.WorkBench/eSuite.WorkBench.sln new file mode 100644 index 0000000..02a57e4 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "eSuite.WorkBench", "eSuite.WorkBench\eSuite.WorkBench.csproj", "{E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}" +EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "eSuite.WorkBench.Installer", "eSuite.WorkBench.Installer\eSuite.WorkBench.Installer.wixproj", "{6AAF4506-6842-4012-9D61-8336719AD0AA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Debug|x86.ActiveCfg = Debug|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Debug|x86.Build.0 = Debug|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Release|Any CPU.Build.0 = Release|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Release|x86.ActiveCfg = Release|Any CPU + {E6D4E7C8-E5C3-4F16-ACDE-F07E2C12DB93}.Release|x86.Build.0 = Release|Any CPU + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Debug|Any CPU.Build.0 = Debug|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Debug|x86.ActiveCfg = Debug|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Debug|x86.Build.0 = Debug|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Release|Any CPU.ActiveCfg = Release|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Release|Any CPU.Build.0 = Release|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Release|x86.ActiveCfg = Release|x86 + {6AAF4506-6842-4012-9D61-8336719AD0AA}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F7A646E3-6CEE-4A1F-B794-923FCD828EC2} + EndGlobalSection +EndGlobal diff --git a/e-suite.WorkBench/eSuite.WorkBench/App.config b/e-suite.WorkBench/eSuite.WorkBench/App.config new file mode 100644 index 0000000..e5b6aca --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/App.config @@ -0,0 +1,31 @@ + + + + +
+ + + + + + + + + + + + + sa + + + Pass1234! + + + False + + + + + + + \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench/App.xaml b/e-suite.WorkBench/eSuite.WorkBench/App.xaml new file mode 100644 index 0000000..ba426bf --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/e-suite.WorkBench/eSuite.WorkBench/App.xaml.cs b/e-suite.WorkBench/eSuite.WorkBench/App.xaml.cs new file mode 100644 index 0000000..5e6160e --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/App.xaml.cs @@ -0,0 +1,19 @@ +using eSuite.WorkBench.IoC; +using System.Windows; + +namespace eSuite.WorkBench +{ + public partial class App : Application + { + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + var iocContainer = new IocContainer(); + iocContainer.Registering += IocRegister.RegisterIocTypes; + + Window mainWindow = (Window)iocContainer.Resolve(); + mainWindow.Show(); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/AssemblyInfo.cs b/e-suite.WorkBench/eSuite.WorkBench/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/BackupDatabaseCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/BackupDatabaseCommand.cs new file mode 100644 index 0000000..abe3e7e --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/BackupDatabaseCommand.cs @@ -0,0 +1,25 @@ +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Threading.Tasks; + +namespace eSuite.WorkBench.Commands +{ + public class BackupDatabaseCommand : AsyncCommandBase + { + private readonly IDbService _dbService; + + public BackupDatabaseCommand(IDbService dbService, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _dbService = dbService; + } + + protected override async Task ExecuteAsync(object parameter) + { + DoFeedbackMessage("Backing up database..."); + await _dbService.BackupDatabaseAsync(); + DoFeedbackMessage("...database backed up"); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/ClearFeedBackCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/ClearFeedBackCommand.cs new file mode 100644 index 0000000..8d644bc --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/ClearFeedBackCommand.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; + +namespace eSuite.WorkBench.Commands; + +public class ClearFeedBackCommand : AsyncCommandBase +{ + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly ICommandsService _commandService; + + public ClearFeedBackCommand(MainWindowViewModel mainWindowViewModel, ICommandsService commandsService, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + IsEnabled = true; + } + + protected override Task ExecuteAsync(object parameter) + { + _mainWindowViewModel.FeedbackOutput = ""; + return Task.CompletedTask; + } + +} \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/DeleteBranchVersionCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/DeleteBranchVersionCommand.cs new file mode 100644 index 0000000..fa36645 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/DeleteBranchVersionCommand.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; + +namespace eSuite.WorkBench.Commands; + +public class DeleteBranchVersionCommand : AsyncCommandBase +{ + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly IContainerRegistryClient _containerRegistryClient; + + public DeleteBranchVersionCommand(MainWindowViewModel mainWindowViewModel, IContainerRegistryClient containerRegistryClient, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _containerRegistryClient = containerRegistryClient; + } + + protected override async Task ExecuteAsync(object parameter) + { + if (_mainWindowViewModel.SelectedBranch == null) + { + return; + } + + var branchFeature = BranchFeature(); + DoFeedbackMessage($"Deleting {branchFeature}"); + + if (branchFeature == "master") + { + branchFeature = string.Empty; + } + + foreach (var imageName in GetAllAvailableVersions(branchFeature, _mainWindowViewModel.AvailableWebUiTags)) + { + await _containerRegistryClient.DeleteImageAsync("e-suite.webui", imageName); + DoFeedbackMessage($"WebUi: {imageName}"); + } + + foreach (var imageName in GetAllAvailableVersions(branchFeature, _mainWindowViewModel.AvailableApiTags)) + { + await _containerRegistryClient.DeleteImageAsync("e-suite.api", imageName); + DoFeedbackMessage($"API: {imageName}"); + } + + foreach (var imageName in GetAllAvailableVersions(branchFeature, _mainWindowViewModel.AvailableDbMigratorTags)) + { + await _containerRegistryClient.DeleteImageAsync("e-suite.database.migrator", imageName); + DoFeedbackMessage($"Migrator: {imageName}"); + } + + foreach (var imageName in GetAllAvailableVersions(branchFeature, _mainWindowViewModel.AvailableSchedulerTags)) + { + await _containerRegistryClient.DeleteImageAsync("e-suite.scheduler", imageName); + DoFeedbackMessage($"Scheduler: {imageName}"); + } + + foreach (var imageName in GetAllAvailableVersions(branchFeature, _mainWindowViewModel.AvailableMessageProcessorTags)) + { + await _containerRegistryClient.DeleteImageAsync("e-suite.messageprocessor", imageName); + DoFeedbackMessage($"Message Processor: {imageName}"); + } + + foreach (var imageName in GetAllAvailableVersions(branchFeature, _mainWindowViewModel.AvailableProxyTags)) + { + await _containerRegistryClient.DeleteImageAsync("e-suite.proxy", imageName); + DoFeedbackMessage($"Proxy: {imageName}"); + } + + DoFeedbackMessage($"{branchFeature} deleted"); + } + + private string BranchFeature() + { + //var branchVersion = parameter as Branch; + var branchVersion = _mainWindowViewModel.SelectedBranch; + var branchFeature = $"{branchVersion.Parent?.BranchName}-{branchVersion.BranchName}".TrimStart('-'); + return branchFeature; + } + + public override bool CanExecute(object parameter) + { + if (!_mainWindowViewModel.DeveloperMode) + return false; + + if (_mainWindowViewModel.SelectedBranch == null) + return false; + + if (!base.CanExecute(parameter)) + return false; + + var branchFeature = BranchFeature(); + switch (branchFeature) + { + case "master": + case "develop": + return false; + default: + return true; + } + } + + private static IEnumerable GetAllAvailableVersions(string branchFeature, IEnumerable availableTags) + { + var tags = branchFeature == string.Empty ? + availableTags.Where(x => !x.Contains("-")) : + availableTags.Where(x => x.Contains(branchFeature)); + + return tags; + } + + private static readonly Regex Regex = new Regex(@"\d+\.\d+\.\d+.\d+"); + + private static List CalcXNumbers(string value) + { + var parts = Regex.Match(value).Value.Split('.'); + + return parts.Select(part => long.Parse(part)).ToList(); + } +} \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/DeleteDatabaseCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/DeleteDatabaseCommand.cs new file mode 100644 index 0000000..21c556a --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/DeleteDatabaseCommand.cs @@ -0,0 +1,27 @@ +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Threading.Tasks; + +namespace eSuite.WorkBench.Commands +{ + public class DeleteDatabaseCommand : AsyncCommandBase + { + private readonly IMainWindowViewModel _mainWindowViewModel; + private readonly IDbService _dbService; + + public DeleteDatabaseCommand(IMainWindowViewModel mainWindowViewModel, IDbService dbService, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _dbService = dbService; + } + + protected override async Task ExecuteAsync(object parameter) + { + DoFeedbackMessage("Deleting database..."); + await _dbService.DropDatabaseAsync(); + DoFeedbackMessage("...database deleted"); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/GetTagListCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/GetTagListCommand.cs new file mode 100644 index 0000000..5e206ba --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/GetTagListCommand.cs @@ -0,0 +1,141 @@ +using eSuite.WorkBench.Models; +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace eSuite.WorkBench.Commands +{ + public class GetTagListCommand : AsyncCommandBase + { + private readonly IContainerRegistryClient _containerRegistryClient; + private readonly MainWindowViewModel _mainWindowViewModel; + + public GetTagListCommand(MainWindowViewModel mainWindowViewModel, IContainerRegistryClient containerRegistryClient, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _containerRegistryClient = containerRegistryClient; + _mainWindowViewModel = mainWindowViewModel; + } + + protected override async Task ExecuteAsync(object parameter) + { + DoFeedbackMessage("Refreshing list..."); + + _mainWindowViewModel.CombinedBranches.Clear(); + _mainWindowViewModel.Branches.Clear(); + + var proxyTags = _containerRegistryClient.GetTagsListAsync("e-suite.proxy"); + var apiTags = _containerRegistryClient.GetTagsListAsync("e-suite.api"); + var uiTags = _containerRegistryClient.GetTagsListAsync("e-suite.webui"); + var dbMigratorTags = _containerRegistryClient.GetTagsListAsync("e-suite.database.migrator"); + var schedulerTags = _containerRegistryClient.GetTagsListAsync("e-suite.scheduler"); + var messageProcessorTags = _containerRegistryClient.GetTagsListAsync("e-suite.messageprocessor"); + + var tasks = new List>> + { + apiTags, + uiTags, + dbMigratorTags, + schedulerTags, + messageProcessorTags + }; + + await Task.WhenAll(tasks); + + foreach (var task in tasks) + GetAllBranches(task.Result); + + foreach (var kv in _mainWindowViewModel.CombinedBranches) + { + var branch = new Branch(kv.Key, default, default); + branch.BranchVersions = kv.Value.GroupBy(x => x) + .Select(g => g.First()) + .Select(x => new Branch(x, null, branch)) + .ToList(); + + _mainWindowViewModel.Branches.Add(branch); + } + + + PopulateTags(proxyTags.Result, _mainWindowViewModel.AvailableProxyTags, _mainWindowViewModel.ProxyBranchesVersions); + PopulateTags(apiTags.Result, _mainWindowViewModel.AvailableApiTags, _mainWindowViewModel.ApiBranchesVersions); + PopulateTags(uiTags.Result, _mainWindowViewModel.AvailableWebUiTags, _mainWindowViewModel.WebUiBranchesVersions); + PopulateTags(dbMigratorTags.Result, _mainWindowViewModel.AvailableDbMigratorTags, + _mainWindowViewModel.DbMigratorBranchesVersions); + PopulateTags(schedulerTags.Result, _mainWindowViewModel.AvailableSchedulerTags, + _mainWindowViewModel.SchedulerBranchesVersions); + PopulateTags(messageProcessorTags.Result, _mainWindowViewModel.AvailableMessageProcessorTags, + _mainWindowViewModel.MessageProcessorBranchesVersions); + DoFeedbackMessage("...finished refreshing list"); + } + + private void PopulateTags(IEnumerable tags, SelectableObservableCollection selectableCollection, Dictionary> dictionary) + { + foreach (var apiTag in tags) + { + selectableCollection.Add(apiTag); + + var tagsList = new List(); + + var branchName = "master"; + var version = apiTag; + var lastSeperator = apiTag.LastIndexOf('-'); + if (lastSeperator != -1) + { + branchName = apiTag.Substring(lastSeperator + 1); + version = apiTag.Substring(0, lastSeperator); + } + + if (dictionary.TryGetValue(branchName, out tagsList)) + { + tagsList.Add(version); + } + else + { + var newTagsList = new List { version }; + dictionary.Add(branchName, newTagsList); + } + } + } + + private void GetAllBranches(IEnumerable tags) + { + foreach (var tag in tags) + { + var branch = tag.Substring(tag.IndexOf('-') + 1); + + if (branch.IndexOf('-') != -1) + { + var feature = branch.Substring(branch.IndexOf('-') + 1); + List featureList; + if (_mainWindowViewModel.CombinedBranches.TryGetValue(branch.Substring(0, branch.IndexOf('-')), out featureList)) + { + if (featureList == null) + { + featureList = new List(); + } + + featureList.Add(feature); + } + else + { + featureList = new List(); + featureList.Add(feature); + + _mainWindowViewModel.CombinedBranches.Add(branch.Substring(0, branch.IndexOf('-')), featureList); + } + } + else + { + if (!_mainWindowViewModel.CombinedBranches.ContainsKey(branch)) + { + _mainWindowViewModel.CombinedBranches.Add(branch, new List()); + } + } + } + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchHealthzCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchHealthzCommand.cs new file mode 100644 index 0000000..0062789 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchHealthzCommand.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; + +namespace eSuite.WorkBench.Commands; + +public class LaunchHealthzCommand : AsyncCommandBase +{ + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly ICommandsService _commandService; + + public LaunchHealthzCommand( + MainWindowViewModel mainWindowViewModel, + ICommandsService commandsService, + Action onException, + EventHandler addFeedbackMessage + ) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + IsEnabled = true; + } + + protected override async Task ExecuteAsync(object parameter) + { + try + { + DoFeedbackMessage("Starting HealthZ"); + + await _commandService.LaunchHealthZ(); + } + catch (Exception ex) + { + DoFeedbackMessage(ex.Message); + } + finally + { + DoFeedbackMessage("...finished"); + } + } +} \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchSwaggerCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchSwaggerCommand.cs new file mode 100644 index 0000000..86fa485 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchSwaggerCommand.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; + +namespace eSuite.WorkBench.Commands; + +public class LaunchSwaggerCommand : AsyncCommandBase +{ + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly ICommandsService _commandService; + + public LaunchSwaggerCommand(MainWindowViewModel mainWindowViewModel, ICommandsService commandsService, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + IsEnabled = true; + } + + protected override async Task ExecuteAsync(object parameter) + { + try + { + DoFeedbackMessage("Starting Swagger"); + + await _commandService.LaunchSwagger(); + } + catch (Exception ex) + { + DoFeedbackMessage(ex.Message); + } + finally + { + DoFeedbackMessage("...finished"); + } + } +} \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchWebUiCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchWebUiCommand.cs new file mode 100644 index 0000000..156b04b --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/LaunchWebUiCommand.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; + +namespace eSuite.WorkBench.Commands; + +public class LaunchWebUiCommand : AsyncCommandBase +{ + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly ICommandsService _commandService; + + public LaunchWebUiCommand(MainWindowViewModel mainWindowViewModel, ICommandsService commandsService, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + IsEnabled = true; + } + + protected override async Task ExecuteAsync(object parameter) + { + try + { + DoFeedbackMessage("Starting WebUi"); + + await _commandService.LaunchWebUi(); + } + catch (Exception ex) + { + DoFeedbackMessage(ex.Message); + } + finally + { + DoFeedbackMessage("...finished"); + } + } +} \ No newline at end of file diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/RestoreDatabaseCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/RestoreDatabaseCommand.cs new file mode 100644 index 0000000..d6481c9 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/RestoreDatabaseCommand.cs @@ -0,0 +1,28 @@ +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; +using System; + +using System.Threading.Tasks; + +namespace eSuite.WorkBench.Commands +{ + public class RestoreDatabaseCommand : AsyncCommandBase + { + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly IDbService _dbService; + + public RestoreDatabaseCommand(MainWindowViewModel mainWindowViewModel, IDbService dbService, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _dbService = dbService; + } + + protected override async Task ExecuteAsync(object parameter) + { + DoFeedbackMessage("Restorting database..."); + await _dbService.RestoreDatabaseAsync(_mainWindowViewModel.DatabaseBackups.SelectedItem); + DoFeedbackMessage("...database restored"); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/SaveUserSettingsCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/SaveUserSettingsCommand.cs new file mode 100644 index 0000000..d329abc --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/SaveUserSettingsCommand.cs @@ -0,0 +1,67 @@ +using eSuite.WorkBench.Helpers; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Threading.Tasks; +using System.Windows.Controls; + +namespace eSuite.WorkBench.Commands +{ + public class SaveUserSettingsCommand : AsyncCommandBase + { + private readonly MainWindowViewModel _mainWindowViewModel; + + public SaveUserSettingsCommand(MainWindowViewModel mainWindowViewModel, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + } + + protected override Task ExecuteAsync(object parameter) + { + PasswordBox passwordBox = parameter as PasswordBox; + if (passwordBox == null) + { + throw new NullReferenceException(); + } + + using(var secureStringDecoder = new SecureStringDecoder(passwordBox.SecurePassword)) + { + _mainWindowViewModel.SettingsPassword = secureStringDecoder.DecodeString(); + } + + Properties.Settings.Default.SqlServerAdminLogin = _mainWindowViewModel.SettingsLogin; + if (!string.IsNullOrWhiteSpace(_mainWindowViewModel.SettingsPassword)) + Properties.Settings.Default.SqlServerAdminPassword = _mainWindowViewModel.SettingsPassword; + Properties.Settings.Default.DeveloperMode = _mainWindowViewModel.DeveloperMode; + Properties.Settings.Default.DevopsPersonalAccessKey = _mainWindowViewModel.DevopsPersonalAccessKey; + Properties.Settings.Default.Save(); + DoFeedbackMessage("Settings Saved"); + return Task.CompletedTask; + } + + public override bool CanExecute(object parameter) + { + if (!base.CanExecute(parameter)) + return false; + + string newPassword; + + PasswordBox passwordBox = parameter as PasswordBox; + using (var secureStringDecoder = new SecureStringDecoder(passwordBox.SecurePassword)) + { + newPassword = secureStringDecoder.DecodeString(); + } + + if (_mainWindowViewModel.SettingsLogin != Properties.Settings.Default.SqlServerAdminLogin) + return true; + if (!string.IsNullOrEmpty(newPassword) && newPassword != Properties.Settings.Default.SqlServerAdminPassword) + return true; + if (_mainWindowViewModel.DeveloperMode != Properties.Settings.Default.DeveloperMode) + return true; + if (Properties.Settings.Default.DevopsPersonalAccessKey != _mainWindowViewModel.DevopsPersonalAccessKey) + return true; + + return false; + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/SelectBranchVersionCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/SelectBranchVersionCommand.cs new file mode 100644 index 0000000..ef54839 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/SelectBranchVersionCommand.cs @@ -0,0 +1,128 @@ +using eSuite.WorkBench.Models; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace eSuite.WorkBench.Commands +{ + public class SelectBranchVersionCommand : AsyncCommandBase + { + private readonly MainWindowViewModel _mainWindowViewModel; + + public SelectBranchVersionCommand(MainWindowViewModel mainWindowViewModel, Action onException, EventHandler addFeedbackMessage) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + } + + protected override Task ExecuteAsync(object parameter) + { + + var branchVersion = parameter as Branch; + var branchFeature = $"{branchVersion.Parent?.BranchName}-{branchVersion.BranchName}".TrimStart('-'); + DoFeedbackMessage($"Selecting {branchFeature}"); + + if (branchFeature == "master") + { + branchFeature = string.Empty; + } + + try + { + _mainWindowViewModel.AvailableProxyTags.SelectedItem = GetBestAvailableVersion(branchFeature, _mainWindowViewModel.AvailableProxyTags); + } + catch (Exception) + { + _mainWindowViewModel.AvailableProxyTags.SelectedItem = string.Empty; + } + + try + { + _mainWindowViewModel.AvailableWebUiTags.SelectedItem = GetBestAvailableVersion(branchFeature, _mainWindowViewModel.AvailableWebUiTags); + } + catch (Exception) + { + _mainWindowViewModel.AvailableWebUiTags.SelectedItem = string.Empty; + } + + try + { + _mainWindowViewModel.AvailableApiTags.SelectedItem = GetBestAvailableVersion(branchFeature, _mainWindowViewModel.AvailableApiTags); + } + catch (Exception) + { + _mainWindowViewModel.AvailableApiTags.SelectedItem = string.Empty; + } + + try + { + _mainWindowViewModel.AvailableDbMigratorTags.SelectedItem = GetBestAvailableVersion(branchFeature, _mainWindowViewModel.AvailableDbMigratorTags); + } + catch (Exception) + { + _mainWindowViewModel.AvailableDbMigratorTags.SelectedItem = string.Empty; + } + + try + { + _mainWindowViewModel.AvailableSchedulerTags.SelectedItem = GetBestAvailableVersion(branchFeature, _mainWindowViewModel.AvailableSchedulerTags); + } + catch (Exception) + { + _mainWindowViewModel.AvailableSchedulerTags.SelectedItem = string.Empty; + } + + try + { + _mainWindowViewModel.AvailableMessageProcessorTags.SelectedItem = GetBestAvailableVersion(branchFeature, _mainWindowViewModel.AvailableMessageProcessorTags); + } + catch (Exception) + { + _mainWindowViewModel.AvailableMessageProcessorTags.SelectedItem = string.Empty; + } + + DoFeedbackMessage($"{branchFeature} selected"); + return Task.CompletedTask; + } + + private static string GetBestAvailableVersion(string branchFeature, IEnumerable availableTags) + { + List tags; + if (branchFeature == string.Empty) + { + tags = availableTags.Where(x => !x.Contains("-")).ToList(); + } + else tags = availableTags.Where(x => x.Contains(branchFeature)).ToList(); + if (!tags.Any()) + { + tags = availableTags.Where(x => x.Contains("develop")).ToList(); + } + + tags.Sort((x, y) => + { + var xNumbers = CalcXNumbers(x); + var yNumbers = CalcXNumbers(y); + + if (xNumbers.Count != yNumbers.Count) + return string.CompareOrdinal(x, y); + + return xNumbers.Select((t, i) => t.CompareTo(yNumbers[i])).FirstOrDefault(order => order != 0); + } ); + + + return tags.Last(); + } + + private static readonly Regex Regex = new(@"\d+\.\d+\.\d+.\d+"); + + private static List CalcXNumbers(string value) + { + var parts = Regex.Match(value).Value.Split('.'); + + return parts.Select(part => long.Parse(part)).ToList(); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/StartContainersCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/StartContainersCommand.cs new file mode 100644 index 0000000..07a58db --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/StartContainersCommand.cs @@ -0,0 +1,97 @@ +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using eSuite.WorkBench.Models; + +namespace eSuite.WorkBench.Commands +{ + public class StartContainersCommand : AsyncCommandBase + { + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly ICommandsService _commandService; + public StartContainersCommand(MainWindowViewModel mainWindowViewModel, ICommandsService commandsService, Action onException, EventHandler addFeedbackMessage ) : base(onException) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + _commandService.FeedbackMessage += commandService_FeedbackMessage; + + IsEnabled = !_commandService.IsAnyContainerRunning(); + } + + private void commandService_FeedbackMessage(object sender, FeedbackEventArgs e) + { + DoFeedbackMessage(e.Message); + } + + public StartContainersCommand(MainWindowViewModel mainWindowViewModel, ICommandsService commandsService, Action onException) : base (onException) + { + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + + IsEnabled = !_commandService.IsAnyContainerRunning(); + } + + protected override async Task ExecuteAsync(object parameter) + { + try + { + DoFeedbackMessage("Starting containers..."); + DoFeedbackMessage("Connecting to container registry"); + await _commandService.ConnectToContainerRegistry(); + + var databaseName = GetBranchName(_mainWindowViewModel.SelectedBranch); + + DoFeedbackMessage($"Database name: {databaseName}"); + + await Task.WhenAll(new List + { + _commandService.StartRabbitMQContainerAsync(), + _commandService.StartDatabaseMigratorContainerAsync(_mainWindowViewModel.AvailableDbMigratorTags.SelectedItem, databaseName), + }); + + await Task.WhenAll(new List + { + _commandService.StartProxyContainerAsync(_mainWindowViewModel.AvailableProxyTags.SelectedItem), + _commandService.StartApiContainerAsync(_mainWindowViewModel.AvailableApiTags.SelectedItem, databaseName), + _commandService.StartWebUiContainerAsync(_mainWindowViewModel.AvailableWebUiTags.SelectedItem), + _commandService.StartSchedulerContainerAsync(_mainWindowViewModel.AvailableSchedulerTags.SelectedItem, databaseName), + _commandService.StartMessageProcessorContainerAsync(_mainWindowViewModel.AvailableMessageProcessorTags.SelectedItem, databaseName) + }); + + _mainWindowViewModel.StopContainersCommand.IsEnabled = await _commandService.IsAnyContainerRunningAsync(); + IsEnabled = !(await _commandService.IsAnyContainerRunningAsync()); + } + catch (Exception ex) + { + DoFeedbackMessage(ex.Message); + } + finally + { + DoFeedbackMessage("...finished"); + } + + } + + private static string GetBranchName(Branch branch) + { + char[] replaceChars = { '.', '-' }; + + var currentBranch = branch; + var branchName = string.Empty; + + while (currentBranch != null) + { + branchName = currentBranch.BranchName + "_" + branchName; + currentBranch = currentBranch.Parent; + } + + foreach (var replaceChar in replaceChars) + branchName = branchName.Replace(replaceChar, '_'); + + return branchName.TrimEnd('_'); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Commands/StopContainersCommand.cs b/e-suite.WorkBench/eSuite.WorkBench/Commands/StopContainersCommand.cs new file mode 100644 index 0000000..b1b9a15 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Commands/StopContainersCommand.cs @@ -0,0 +1,30 @@ +using eSuite.WorkBench.Services; +using eSuite.WorkBench.WpfHelper; +using System; +using System.Threading.Tasks; + +namespace eSuite.WorkBench.Commands +{ + public class StopContainersCommand : AsyncCommandBase + { + private readonly MainWindowViewModel _mainWindowViewModel; + private readonly ICommandsService _commandService; + + public StopContainersCommand(MainWindowViewModel mainWindowViewModel, ICommandsService commandsService, Action onExeception, EventHandler addFeedbackMessage) : base(onExeception) + { + FeedbackMessage += addFeedbackMessage; + _mainWindowViewModel = mainWindowViewModel; + _commandService = commandsService; + IsEnabled = _commandService.IsAnyContainerRunning(); + } + + protected override async Task ExecuteAsync(object parameter) + { + DoFeedbackMessage("Stopping containers..."); + await _commandService.StopContainersAsync(); + IsEnabled = await _commandService.IsAnyContainerRunningAsync(); + _mainWindowViewModel.StartContainersCommand.IsEnabled = !(IsEnabled); + DoFeedbackMessage("...containers stopped"); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/FeedbackEventArgs.cs b/e-suite.WorkBench/eSuite.WorkBench/FeedbackEventArgs.cs new file mode 100644 index 0000000..44441d2 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/FeedbackEventArgs.cs @@ -0,0 +1,9 @@ +using System; + +namespace eSuite.WorkBench +{ + public class FeedbackEventArgs : EventArgs + { + public string Message { get; set; } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/Helpers/SecureStringDecoder.cs b/e-suite.WorkBench/eSuite.WorkBench/Helpers/SecureStringDecoder.cs new file mode 100644 index 0000000..33da7ec --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/Helpers/SecureStringDecoder.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.InteropServices; +using System.Security; + +namespace eSuite.WorkBench.Helpers +{ + public class SecureStringDecoder : IDisposable + { + private readonly SecureString _secureString; + + IntPtr intPtr = IntPtr.Zero; + + public SecureStringDecoder(SecureString secureString) + { + _secureString = secureString; + intPtr = Marshal.SecureStringToGlobalAllocUnicode(_secureString); + } + + public string DecodeString() + { + return Marshal.PtrToStringUni(intPtr); + } + + public void Dispose() + { + Marshal.ZeroFreeGlobalAllocUnicode(intPtr); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IMainWindow.cs b/e-suite.WorkBench/eSuite.WorkBench/IMainWindow.cs new file mode 100644 index 0000000..dca1bd2 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IMainWindow.cs @@ -0,0 +1,6 @@ +namespace eSuite.WorkBench +{ + public interface IMainWindow + { + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IMainWindowViewModel.cs b/e-suite.WorkBench/eSuite.WorkBench/IMainWindowViewModel.cs new file mode 100644 index 0000000..5326c91 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IMainWindowViewModel.cs @@ -0,0 +1,6 @@ +namespace eSuite.WorkBench +{ + public interface IMainWindowViewModel + { + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/IIocContainer.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/IIocContainer.cs new file mode 100644 index 0000000..fac9335 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/IIocContainer.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace eSuite.WorkBench.IoC +{ + public interface IIocContainer + { + T Resolve(); + + T Resolve(IEnumerable parameters); + + event IocContainerRegisteringEventHandler Registering; + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainer.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainer.cs new file mode 100644 index 0000000..f0be858 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainer.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using Autofac; + +namespace eSuite.WorkBench.IoC +{ + public class IocContainer : IIocContainer + { + private IContainer _container; + + public event IocContainerRegisteringEventHandler Registering; + + private void BuildContainer() + { + List iocRegistrations = new List + { + new IocRegistration {Object = this, Type = typeof(IIocContainer), Singleton = true} + }; + + DoRegistering(iocRegistrations); + + var containerBuilder = new ContainerBuilder(); + + foreach (IocRegistration iocRegistration in iocRegistrations) + { + if (iocRegistration.Singleton) + { + if (iocRegistration.Object is Type type) + { + containerBuilder.RegisterType(type).As(iocRegistration.Type).SingleInstance(); + } + else + { + containerBuilder.RegisterInstance(iocRegistration.Object).As(iocRegistration.Type).SingleInstance(); + } + } + else + { + if (iocRegistration.Object is Type type) + { + containerBuilder.RegisterType(type).As(iocRegistration.Type); + } + else + { + throw new ArgumentException("Cannot register instance for object as non singleton."); + } + } + } + + _container = containerBuilder.Build(); + } + + private void DoRegistering(List iocRegistrations) + { + if (Registering != null) + { + var args = new IocContainerRegisteringEventArgs + { + IocRegistrations = iocRegistrations + }; + + Registering(this, args); + } + } + + public T Resolve() + { + if (_container == null) + BuildContainer(); + + return _container.Resolve(); + } + + public T Resolve(IEnumerable parameters) + { + if (_container == null) + BuildContainer(); + + List parameterList = new List(); + + foreach (var parameter in parameters) + { + if (parameter is TypedParameter typedParameter) + { + parameterList.Add(AddTypedParameter(typedParameter)); + } + else if (parameter is NamedParameter namedParameter) + { + parameterList.Add(AddNamedParameter(namedParameter)); + } + } + + return _container.Resolve(parameterList); + } + + private Autofac.Core.Parameter AddNamedParameter(NamedParameter parameter) + { + return new Autofac.NamedParameter(parameter.Name, parameter.Value); + } + + private Autofac.Core.Parameter AddTypedParameter(TypedParameter parameter) + { + return new Autofac.TypedParameter(parameter.Type, parameter.Value); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainerRegisteringEventArgs.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainerRegisteringEventArgs.cs new file mode 100644 index 0000000..16eb583 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainerRegisteringEventArgs.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace eSuite.WorkBench.IoC +{ + public class IocContainerRegisteringEventArgs + { + public List IocRegistrations { get; set; } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainerRegisteringEventHandler.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainerRegisteringEventHandler.cs new file mode 100644 index 0000000..722eb76 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocContainerRegisteringEventHandler.cs @@ -0,0 +1,4 @@ +namespace eSuite.WorkBench.IoC +{ + public delegate void IocContainerRegisteringEventHandler(object sender, IocContainerRegisteringEventArgs e); +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/IocRegistration.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocRegistration.cs new file mode 100644 index 0000000..2845c72 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/IocRegistration.cs @@ -0,0 +1,11 @@ +using System; + +namespace eSuite.WorkBench.IoC +{ + public class IocRegistration + { + public Object Object { get; set; } + public Type Type { get; set; } + public bool Singleton { get; set; } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/Parameter.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/Parameter.cs new file mode 100644 index 0000000..3d4408d --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/Parameter.cs @@ -0,0 +1,7 @@ +namespace eSuite.WorkBench.IoC +{ + public class Parameter + { + public object Value { get; set; } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IoC/TypedParameter.cs b/e-suite.WorkBench/eSuite.WorkBench/IoC/TypedParameter.cs new file mode 100644 index 0000000..76f8822 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IoC/TypedParameter.cs @@ -0,0 +1,14 @@ +using System; + +namespace eSuite.WorkBench.IoC +{ + public class TypedParameter : Parameter + { + public Type Type { get; set; } + } + + public class NamedParameter : Parameter + { + public string Name { get; set; } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/IocRegister.cs b/e-suite.WorkBench/eSuite.WorkBench/IocRegister.cs new file mode 100644 index 0000000..f2d1468 --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/IocRegister.cs @@ -0,0 +1,19 @@ +using e_suiteRunner.Services; +using eSuite.WorkBench.IoC; +using eSuite.WorkBench.Services; + +namespace eSuite.WorkBench +{ + public static class IocRegister + { + public static void RegisterIocTypes(object sender, IocContainerRegisteringEventArgs e) + { + e.IocRegistrations.Add(new IocRegistration { Object = typeof(MainWindow), Type = typeof(IMainWindow), Singleton = false }); + e.IocRegistrations.Add(new IocRegistration { Object = typeof(MainWindowViewModel), Type = typeof(IMainWindowViewModel), Singleton = false }); + e.IocRegistrations.Add(new IocRegistration { Object = typeof(CommandsService), Type = typeof(ICommandsService), Singleton = false }); + e.IocRegistrations.Add(new IocRegistration { Object = typeof(DbService), Type = typeof(IDbService), Singleton = false }); + e.IocRegistrations.Add(new IocRegistration { Object = typeof(ContainerRegistryClient), Type = typeof(IContainerRegistryClient), Singleton = true }); + e.IocRegistrations.Add(new IocRegistration { Object = typeof(UpdateChecker), Type = typeof(IUpdateChecker), Singleton = true }); + } + } +} diff --git a/e-suite.WorkBench/eSuite.WorkBench/MainWindow.xaml b/e-suite.WorkBench/eSuite.WorkBench/MainWindow.xaml new file mode 100644 index 0000000..569e4bc --- /dev/null +++ b/e-suite.WorkBench/eSuite.WorkBench/MainWindow.xaml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + Branches + + + + + + +