diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..cd967fc
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,25 @@
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/.idea
+**/*.*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/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 0473985..c8617dc 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -1,9 +1,7 @@
-# This workflow will build a .NET project
-# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
-
-name: .NET
+name: .NET - Build NuGet and Publish
on:
+ workflow_dispatch:
push:
branches: [ "main" ]
pull_request:
@@ -11,25 +9,66 @@ on:
jobs:
build:
+ name: Build and analyze
+ runs-on: windows-latest
+ env:
+ ProjectName: 'AStar.Dev.Admin.Api.Client.Sdk'
+ RepositoryName: 'astar-dev-admin-api-client-sdk'
+ steps:
+ - name: Set up JDK
+ uses: actions/setup-java@v4.4.0
+ with:
+ java-version: 17
+ distribution: 'zulu'
- runs-on: ubuntu-latest
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
- steps:
- - uses: actions/checkout@v4
-
- - name: Setup .NET
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: 9.0.x
-
- - name: Delete nuget*.config files
- run: rm -f nuget*.config
-
- - name: Restore dependencies
- run: dotnet restore
-
- - name: Build
- run: dotnet build --no-restore
-
- - name: Test
- run: dotnet test --no-build --verbosity normal
+ - name: Checkout
+ uses: actions/checkout@v4.2.1
+ with:
+ fetch-depth: 0
+
+ - name: Cache SonarCloud packages
+ uses: actions/cache@v4.2.3
+ with:
+ path: ~\sonar\cache
+ key: ${{ runner.os }}-sonar
+ restore-keys: ${{ runner.os }}-sonar
+
+ - name: Cache SonarCloud scanner
+ id: cache-sonar-scanner
+ uses: actions/cache@v4.2.3
+ with:
+ path: .\.sonar\scanner
+ key: ${{ runner.os }}-sonar-scanner
+ restore-keys: ${{ runner.os }}-sonar-scanner
+
+ - name: Install SonarCloud scanner
+ if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
+ shell: powershell
+ run: |
+ New-Item -Path .\.sonar\scanner -ItemType Directory
+ dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
+
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ shell: powershell
+ run: |
+ dotnet tool install --global dotnet-coverage
+ .\.sonar\scanner\dotnet-sonarscanner begin /k:"astar-development_${{ env.RepositoryName }}" /o:"astar-development" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.scanner.scanAll=false
+ dotnet build --configuration Release
+ dotnet-coverage collect 'dotnet test --filter "FullyQualifiedName!~Acceptance.Tests"' -f xml -o 'coverage.xml'
+ .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
+
+ - name: Pack NuGet package
+ if: github.ref == 'refs/heads/main'
+ run: dotnet pack .\src\${{ env.ProjectName }}\${{ env.ProjectName }}.csproj
+
+ - name: Push to NuGet
+ if: github.ref == 'refs/heads/main'
+ run: dotnet nuget push "**\${{ env.ProjectName }}.*.nupkg" --api-key ${{secrets.nuget_api_key}} --skip-duplicate --source https://api.nuget.org/v3/index.json
diff --git a/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/.gitignore b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/.gitignore
new file mode 100644
index 0000000..fbd23cc
--- /dev/null
+++ b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/projectSettingsUpdater.xml
+/modules.xml
+/.idea.AStar.Dev.Admin.Api.Client.Sdk.iml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/.name b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/.name
new file mode 100644
index 0000000..c79273f
--- /dev/null
+++ b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/.name
@@ -0,0 +1 @@
+AStar.Dev.Admin.Api.Client.Sdk
\ No newline at end of file
diff --git a/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/indexLayout.xml b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/vcs.xml b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/vcs.xml
new file mode 100644
index 0000000..8306744
--- /dev/null
+++ b/.idea/.idea.AStar.Dev.Admin.Api.Client.Sdk/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AStar.Dev.Admin.Api.Client.Sdk.sln b/AStar.Dev.Admin.Api.Client.Sdk.sln
new file mode 100644
index 0000000..a9dc473
--- /dev/null
+++ b/AStar.Dev.Admin.Api.Client.Sdk.sln
@@ -0,0 +1,47 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F881F2A5-6B1D-4E4F-A698-C3D5E760E509}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F205434D-6BE3-414B-A17D-A12F8E78C58F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Admin.Api.Client.Sdk", "src\AStar.Dev.Admin.Api.Client.Sdk\AStar.Dev.Admin.Api.Client.Sdk.csproj", "{1A33B6F9-9126-43D5-962B-6BA2DBE5B052}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit", "test\AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit\AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit.csproj", "{20915888-5AEA-4918-8DE4-FBE77EFCC758}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{94A53025-23C4-4B9D-B015-B7CDBD1E2275}"
+ ProjectSection(SolutionItems) = preProject
+ .github\dependabot.yml = .github\dependabot.yml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{790D531F-FFB9-4C8C-A861-C469CDF5DB9D}"
+ ProjectSection(SolutionItems) = preProject
+ .github\workflows\dotnet.yml = .github\workflows\dotnet.yml
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1A33B6F9-9126-43D5-962B-6BA2DBE5B052} = {F881F2A5-6B1D-4E4F-A698-C3D5E760E509}
+ {20915888-5AEA-4918-8DE4-FBE77EFCC758} = {F205434D-6BE3-414B-A17D-A12F8E78C58F}
+ {790D531F-FFB9-4C8C-A861-C469CDF5DB9D} = {94A53025-23C4-4B9D-B015-B7CDBD1E2275}
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1A33B6F9-9126-43D5-962B-6BA2DBE5B052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1A33B6F9-9126-43D5-962B-6BA2DBE5B052}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1A33B6F9-9126-43D5-962B-6BA2DBE5B052}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1A33B6F9-9126-43D5-962B-6BA2DBE5B052}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20915888-5AEA-4918-8DE4-FBE77EFCC758}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20915888-5AEA-4918-8DE4-FBE77EFCC758}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20915888-5AEA-4918-8DE4-FBE77EFCC758}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20915888-5AEA-4918-8DE4-FBE77EFCC758}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/AStar.Dev.Example.sln.sln b/AStar.Dev.Example.sln.sln
deleted file mode 100644
index be68fef..0000000
--- a/AStar.Dev.Example.sln.sln
+++ /dev/null
@@ -1,57 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ADD5430F-CD80-42C7-80DA-90048E210EE7}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{73794993-9898-4968-AF19-C3E7450C94E4}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Example.ClassLib", "src\AStar.Dev.Example.ClassLib\AStar.Dev.Example.ClassLib.csproj", "{A9C19332-40FE-4E24-A890-405D46CD72A5}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "end-to-end", "end-to-end", "{F1C7FB9E-2F0F-41C9-822A-7320339193CA}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{D724595D-C6BC-4F31-9D2A-4F4707436F10}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{10DD984D-6788-4E04-A89C-3270006F5C56}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Example.ClassLib.Tests.Unit", "test\unit\AStar.Dev.Example.ClassLib.Tests.Unit\AStar.Dev.Example.ClassLib.Tests.Unit.csproj", "{1D7D41F6-3866-4C00-A1BA-1675227FA9FA}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E1CEEE40-22D0-4F7B-AB2B-A308F8DE6A54}"
- ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- .gitignore = .gitignore
- build-and-test.ps1 = build-and-test.ps1
- CodeMaid.config = CodeMaid.config
- LICENSE = LICENSE
- nuget.ci.config = nuget.ci.config
- nuget.config = nuget.config
- README.md = README.md
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {A9C19332-40FE-4E24-A890-405D46CD72A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A9C19332-40FE-4E24-A890-405D46CD72A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A9C19332-40FE-4E24-A890-405D46CD72A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A9C19332-40FE-4E24-A890-405D46CD72A5}.Release|Any CPU.Build.0 = Release|Any CPU
- {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {A9C19332-40FE-4E24-A890-405D46CD72A5} = {ADD5430F-CD80-42C7-80DA-90048E210EE7}
- {F1C7FB9E-2F0F-41C9-822A-7320339193CA} = {73794993-9898-4968-AF19-C3E7450C94E4}
- {D724595D-C6BC-4F31-9D2A-4F4707436F10} = {73794993-9898-4968-AF19-C3E7450C94E4}
- {10DD984D-6788-4E04-A89C-3270006F5C56} = {73794993-9898-4968-AF19-C3E7450C94E4}
- {1D7D41F6-3866-4C00-A1BA-1675227FA9FA} = {10DD984D-6788-4E04-A89C-3270006F5C56}
- EndGlobalSection
-EndGlobal
diff --git a/AStar.ico b/AStar.ico
new file mode 100644
index 0000000..0b9aea4
Binary files /dev/null and b/AStar.ico differ
diff --git a/AStar.png b/AStar.png
new file mode 100644
index 0000000..8cac0a1
Binary files /dev/null and b/AStar.png differ
diff --git a/CodeMaid.config b/CodeMaid.config
deleted file mode 100644
index 54f2ebe..0000000
--- a/CodeMaid.config
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- <?xml version="1.0" encoding="utf-16"?>
- <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <string>ReSharper disable </string>
- <string>ReSharper enable </string>
- </ArrayOfString>
-
-
-
- True
-
-
- 1
-
-
- False
-
-
- True
-
-
- True
-
-
- 1
-
-
- 2
-
-
- True
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
- True
-
-
- 1
-
-
-
-
\ No newline at end of file
diff --git a/nuget.ci.config b/nuget.ci.config
deleted file mode 100644
index aa5beec..0000000
--- a/nuget.ci.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/nuget.config b/nuget.config
deleted file mode 100644
index 782724b..0000000
--- a/nuget.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.csproj b/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.csproj
new file mode 100644
index 0000000..a48272c
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.csproj
@@ -0,0 +1,65 @@
+
+
+
+ latest-recommended
+ AStar Developement, Jason Barden
+ AStar Development
+ AStar Developement, 2025
+ This package contains the currently supported methods for interacting with the Admin API whilst abstracting the details..
+ $(AssemblyName).xml
+ True
+ True
+ true
+ enable
+ True
+ true
+ enable
+ AStar.png
+ LICENSE
+ https://github.com/astar-development/
+ Readme.md
+ Update.
+ True
+ git
+ https://github.com/astar-development/
+ snupkg
+ net9.0
+ AStar.Dev.Admin.Api.Client.Sdk
+ 3a340cb0-60ee-4e38-93ac-0f8829c7193d
+ 0.1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ 1701;1702;
+
+
+
+ True
+ 1701;1702;
+
+
+
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.xml b/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.xml
new file mode 100644
index 0000000..54d3e7e
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.xml
@@ -0,0 +1,333 @@
+
+
+
+ AStar.Dev.Admin.Api.Client.Sdk
+
+
+
+
+ The class.
+
+
+
+
+ The class.
+
+
+
+
+
+
+
+
+
+
+ The GetSiteConfigurationAsync method will get the User Configuration.
+
+ The Site Configuration - populated or empty
+
+
+
+ The GetModelsToIgnoreAsync method will get the models to ignore.
+
+ A collection of 0 or more models to ignore
+
+
+
+ The GetScrapeDirectoriesAsync method will get the Scrape Directories.
+
+ The Scrape Directories - populated or empty
+
+
+
+ The GetSearchConfigurationAsync method will get the Search Configuration.
+
+ The Search Configuration - populated or empty
+
+
+
+ The GetTagsToIgnoreAsync method will get the Tags to Ignore.
+
+ A collection of 0 or more Tags to Ignore
+
+
+
+ The class containing the current configuration settings.
+
+
+
+
+ Gets the Section Location for the API configuration from within the appSettings.Json file.
+
+
+
+
+
+
+
+
+
+
+ The class containing the project-specific constants.
+
+
+
+
+ Gets the Api Name.
+
+
+
+
+ The class.
+
+
+
+
+ Gets or sets the value of the Model to ignore completely. I know, shocking...
+
+
+
+
+ Returns this object in JSON format
+
+
+ This object serialized as a JSON object.
+
+
+
+
+ The class containing the Scrape Directories Configuration.
+
+
+
+
+ Gets or sets The ID of the configuration.
+
+
+
+
+ Gets or sets the Root Directory for everything - search and save.
+
+
+
+
+ Gets or sets the Base Save Directory for the saving post search - appended to the root directory.
+
+
+
+
+ Gets or sets the Base Directory for the search checks - appended to the root directory.
+
+
+
+
+ Gets or sets the Base Directory Famous for the search checks for famous people - appended to the root directory.
+
+
+
+
+ Gets or sets the default subdirectory name for the save - appended to the root directory.
+
+
+
+
+ The class containing the full Search Category definition
+
+
+
+
+ Gets or sets The ID of the search category.
+
+
+
+
+ Gets or sets the Order of the search category - i.e. which category should be 1st, 2nd, etc.
+
+
+
+
+ Gets or sets the Name of the category.
+
+
+
+
+ Gets or sets the Last Known Image Count.
+
+
+
+
+ Gets or sets the Last Page Visited number.
+
+
+
+
+ Gets or sets the Total Pages for the results.
+
+
+
+
+ The class containing the full Search Configuration.
+
+
+
+
+ Gets or sets The ID of the configuration.
+
+
+
+
+ Gets or sets the Base Url for the login and search.
+
+
+
+
+ Gets or sets the Login Url.
+
+
+
+
+ Gets or sets the Search Categories.
+
+
+
+
+ Gets or sets the default Search String.
+
+
+
+
+ Gets or sets the TopWallpapers something.
+
+
+
+
+ Gets or sets the Search String Prefix.
+
+
+
+
+ Gets or sets the Search StringSuffix.
+
+
+
+
+ Gets or sets the Subscriptions something.
+
+
+
+
+ Gets or sets the base Image Pause In Seconds.
+
+
+
+
+ Gets or sets the Starting Page Number.
+
+
+
+
+ Gets or sets the Total Pages for the New Subscription search.
+
+
+
+
+ Gets or sets the Use Headless to determine whether to run in headless mode or not.
+
+
+
+
+ Gets or sets the Subscriptions Starting Page Number.
+
+
+
+
+ Gets or sets the Subscriptions Total Pages.
+
+
+
+
+ Gets or sets the Top Wallpapers Total Pages.
+
+
+
+
+ Gets or sets the Top Wallpapers Starting Page Number.
+
+
+
+
+ The class containing Site Configuration.
+
+
+
+
+ Gets or sets The ID of the configuration
+
+
+
+
+ Gets or sets the Login Email Address
+
+
+
+
+ Gets or sets the Username
+
+
+
+
+ Gets or sets the Password
+
+
+
+
+ Gets or sets the Site Configuration Slug
+
+
+
+
+ Gets or sets the Base URL
+
+
+
+
+ Gets or sets the Login URL
+
+
+
+
+ The class.
+
+
+
+
+ Gets or sets the value of the tag to ignore. I know, shocking...
+
+
+
+
+ Gets or sets the Ignore Image property. When set to true, the image is ignored irrespective of any other
+ setting.
+
+
+
+
+ Returns this object in JSON format
+
+
+ This object serialized as a JSON object.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.ico b/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.ico
new file mode 100644
index 0000000..0b9aea4
Binary files /dev/null and b/src/AStar.Dev.Admin.Api.Client.Sdk/AStar.ico differ
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiClient.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiClient.cs
new file mode 100644
index 0000000..5ab246f
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiClient.cs
@@ -0,0 +1,105 @@
+using System.Net.Http.Json;
+using System.Text.Json;
+using AStar.Dev.Admin.Api.Client.Sdk.Models;
+using AStar.Dev.Api.HealthChecks;
+using AStar.Dev.Functional.Extensions;
+using AStar.Dev.Logging.Extensions;
+using AStar.Dev.Technical.Debt.Reporting;
+using AStar.Dev.Utilities;
+using Microsoft.Identity.Web;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+///
+/// The class.
+///
+public sealed class AdminApiClient(HttpClient httpClient, ITokenAcquisition tokenAcquisitionService, ILoggerAstar logger) : IApiClient
+{
+ private static readonly JsonSerializerOptions JsonSerializerOptions = new(JsonSerializerDefaults.Web);
+
+ ///
+ [Refactor(1,1,"Remove from the Interface")]public async Task GetHealthAsync(CancellationToken cancellationToken = default)
+ {
+ logger.LogHealthCheckStart(Constants.ApiName);
+
+ try
+ {
+ var response = await httpClient.GetAsync("/health/ready", cancellationToken);
+
+ return response.IsSuccessStatusCode
+ ? (await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(cancellationToken), JsonSerializerOptions, cancellationToken))!
+ : logger.ReturnLoggedFailure(response, Constants.ApiName);
+ }
+ catch (HttpRequestException ex)
+ {
+ logger.LogException(ex);
+
+ return new() { Status = $"Could not get a response from the {Constants.ApiName}." };
+ }
+ }
+
+ ///
+ public async Task> GetHealthCheckAsync(CancellationToken cancellationToken = new ())
+ => await GetSafelyAsync("/health/ready?version=1.0");
+
+ ///
+ /// The GetSiteConfigurationAsync method will get the User Configuration.
+ ///
+ /// The Site Configuration - populated or empty
+ public async Task>> GetSiteConfigurationAsync()
+ => await GetSafelyAsync>("site-configurations?version=1.0");
+
+ ///
+ /// The GetModelsToIgnoreAsync method will get the models to ignore.
+ ///
+ /// A collection of 0 or more models to ignore
+ public async Task>> GetModelsToIgnoreAsync()
+ => await GetSafelyAsync>("models-to-ignore?version=1");
+
+ ///
+ /// The GetScrapeDirectoriesAsync method will get the Scrape Directories.
+ ///
+ /// The Scrape Directories - populated or empty
+ public async Task> GetScrapeDirectoriesAsync()
+ => await GetSafelyAsync("scrape-directories?version=1");
+
+ ///
+ /// The GetSearchConfigurationAsync method will get the Search Configuration.
+ ///
+ /// The Search Configuration - populated or empty
+ public async Task> GetSearchConfigurationAsync()
+ => await GetSafelyAsync("search-configuration?version=1");
+
+ ///
+ /// The GetTagsToIgnoreAsync method will get the Tags to Ignore.
+ ///
+ /// A collection of 0 or more Tags to Ignore
+ public async Task>> GetTagsToIgnoreAsync()
+ => await GetSafelyAsync>("search-configuration?version=1");
+
+ private async Task> GetSafelyAsync( string uri)
+ {
+ try
+ {
+ logger.LogApiCallStart(Constants.ApiName, uri);
+ var token = await tokenAcquisitionService.GetAccessTokenForUserAsync(["api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"]);
+
+ _ = httpClient.AddBearerToken(token);
+ var response = await httpClient.GetAsync(uri);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ return logger.ReturnLoggedFailure( Constants.ApiName, uri, response.ReasonPhrase ?? response.StatusCode.ToString());
+ }
+
+ var result = (await response.Content.ReadFromJsonAsync(Utilities.Constants.WebDeserialisationSettings))!;
+ return logger.ReturnLoggedSuccess(result, Constants.ApiName, "uri");
+ }
+ catch(Exception ex)
+ {
+ logger.LogException(ex);
+
+ return Result.Failure(ex.Message)!;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiConfiguration.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiConfiguration.cs
new file mode 100644
index 0000000..f591ca4
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiConfiguration.cs
@@ -0,0 +1,23 @@
+using System.ComponentModel.DataAnnotations;
+using AStar.Dev.Api.Client.Sdk.Shared;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+///
+/// The class containing the current configuration settings.
+///
+public sealed class AdminApiConfiguration : IApiConfiguration
+{
+ ///
+ /// Gets the Section Location for the API configuration from within the appSettings.Json file.
+ ///
+ public const string SectionLocation = "apiConfiguration:adminApiConfiguration";
+
+ ///
+ [Required]
+ public Uri BaseUrl { get; set; } = new("https://not.set.com");
+
+ ///
+ [Required]
+ public required string[] Scopes { get; set; }
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Constants.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Constants.cs
new file mode 100644
index 0000000..2d4d1df
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Constants.cs
@@ -0,0 +1,12 @@
+namespace AStar.Dev.Admin.Api.Client.Sdk;
+
+///
+/// The class containing the project-specific constants.
+///
+public static class Constants
+{
+ ///
+ /// Gets the Api Name.
+ ///
+ public const string ApiName = "AStar.Dev.Admin.Api";
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/LICENSE b/src/AStar.Dev.Admin.Api.Client.Sdk/LICENSE
new file mode 100644
index 0000000..0b1b024
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 AStar Development, Jason Barden
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Models/ModelToIgnore.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/ModelToIgnore.cs
new file mode 100644
index 0000000..51eba12
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/ModelToIgnore.cs
@@ -0,0 +1,23 @@
+using AStar.Dev.Utilities;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+///
+/// The class.
+///
+public sealed class ModelToIgnore
+{
+ ///
+ /// Gets or sets the value of the Model to ignore completely. I know, shocking...
+ ///
+ public string Value { get; set; } = string.Empty;
+
+ ///
+ /// Returns this object in JSON format
+ ///
+ ///
+ /// This object serialized as a JSON object.
+ ///
+ public override string ToString()
+ => this.ToJson();
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Models/ScrapeDirectories.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/ScrapeDirectories.cs
new file mode 100644
index 0000000..a6df0d3
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/ScrapeDirectories.cs
@@ -0,0 +1,37 @@
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+///
+/// The class containing the Scrape Directories Configuration.
+///
+public sealed class ScrapeDirectories
+{
+ ///
+ /// Gets or sets The ID of the configuration.
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the Root Directory for everything - search and save.
+ ///
+ public string RootDirectory { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Base Save Directory for the saving post search - appended to the root directory.
+ ///
+ public string BaseSaveDirectory { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Base Directory for the search checks - appended to the root directory.
+ ///
+ public string BaseDirectory { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Base Directory Famous for the search checks for famous people - appended to the root directory.
+ ///
+ public string BaseDirectoryFamous { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the default subdirectory name for the save - appended to the root directory.
+ ///
+ public string SubDirectoryName { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SearchCategory.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SearchCategory.cs
new file mode 100644
index 0000000..c8d85af
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SearchCategory.cs
@@ -0,0 +1,37 @@
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+///
+/// The class containing the full Search Category definition
+///
+public sealed class SearchCategory
+{
+ ///
+ /// Gets or sets The ID of the search category.
+ ///
+ public string Id { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Order of the search category - i.e. which category should be 1st, 2nd, etc.
+ ///
+ public int Order { get; set; }
+
+ ///
+ /// Gets or sets the Name of the category.
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Last Known Image Count.
+ ///
+ public int LastKnownImageCount { get; set; }
+
+ ///
+ /// Gets or sets the Last Page Visited number.
+ ///
+ public int LastPageVisited { get; set; }
+
+ ///
+ /// Gets or sets the Total Pages for the results.
+ ///
+ public int TotalPages { get; set; }
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SearchConfiguration.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SearchConfiguration.cs
new file mode 100644
index 0000000..7ad38b4
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SearchConfiguration.cs
@@ -0,0 +1,92 @@
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+///
+/// The class containing the full Search Configuration.
+///
+public sealed class SearchConfiguration
+{
+ ///
+ /// Gets or sets The ID of the configuration.
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the Base Url for the login and search.
+ ///
+ public string BaseUrl { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Login Url.
+ ///
+ public string LoginUrl { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Search Categories.
+ ///
+ public IList SearchCategories { get; set; } = [];
+
+ ///
+ /// Gets or sets the default Search String.
+ ///
+ public string SearchString { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the TopWallpapers something.
+ ///
+ public string TopWallpapers { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Search String Prefix.
+ ///
+ public string SearchStringPrefix { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Search StringSuffix.
+ ///
+ public string SearchStringSuffix { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Subscriptions something.
+ ///
+ public string Subscriptions { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the base Image Pause In Seconds.
+ ///
+ public int ImagePauseInSeconds { get; set; }
+
+ ///
+ /// Gets or sets the Starting Page Number.
+ ///
+ public int StartingPageNumber { get; set; }
+
+ ///
+ /// Gets or sets the Total Pages for the New Subscription search.
+ ///
+ public int TotalPages { get; set; }
+
+ ///
+ /// Gets or sets the Use Headless to determine whether to run in headless mode or not.
+ ///
+ public bool UseHeadless { get; set; }
+
+ ///
+ /// Gets or sets the Subscriptions Starting Page Number.
+ ///
+ public int SubscriptionsStartingPageNumber { get; set; }
+
+ ///
+ /// Gets or sets the Subscriptions Total Pages.
+ ///
+ public int SubscriptionsTotalPages { get; set; }
+
+ ///
+ /// Gets or sets the Top Wallpapers Total Pages.
+ ///
+ public int TopWallpapersTotalPages { get; set; }
+
+ ///
+ /// Gets or sets the Top Wallpapers Starting Page Number.
+ ///
+ public int TopWallpapersStartingPageNumber { get; set; }
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SiteConfiguration.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SiteConfiguration.cs
new file mode 100644
index 0000000..bfba4e2
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/SiteConfiguration.cs
@@ -0,0 +1,42 @@
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+///
+/// The class containing Site Configuration.
+///
+public sealed class SiteConfiguration
+{
+ ///
+ /// Gets or sets The ID of the configuration
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the Login Email Address
+ ///
+ public string LoginEmailAddress { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Username
+ ///
+ public string Username { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Password
+ ///
+ public string Password { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Site Configuration Slug
+ ///
+ public string SiteConfigurationSlug { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Base URL
+ ///
+ public string BaseUrl { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Login URL
+ ///
+ public string LoginUrl { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Models/TagToIgnore.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/TagToIgnore.cs
new file mode 100644
index 0000000..2b38a1a
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Models/TagToIgnore.cs
@@ -0,0 +1,29 @@
+using AStar.Dev.Utilities;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+///
+/// The class.
+///
+public sealed class TagToIgnore
+{
+ ///
+ /// Gets or sets the value of the tag to ignore. I know, shocking...
+ ///
+ public string Value { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the Ignore Image property. When set to true, the image is ignored irrespective of any other
+ /// setting.
+ ///
+ public bool IgnoreImage { get; set; }
+
+ ///
+ /// Returns this object in JSON format
+ ///
+ ///
+ /// This object serialized as a JSON object.
+ ///
+ public override string ToString()
+ => this.ToJson();
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/Readme.md b/src/AStar.Dev.Admin.Api.Client.Sdk/Readme.md
new file mode 100644
index 0000000..10a241f
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/Readme.md
@@ -0,0 +1,24 @@
+# AStar.Dev.Admin.Api.Client.Sdk
+
+This NuGet package, as the name suggests, contains the Client SDK for accessing the AStar.Dev.Admin.Api
+
+Methods include calling the healthcheck endpoint and various configuration-related endpoints
+
+## GitHub build
+
+[](https://github.com/astar-development/astar-dev-admin-api-client-sdk/actions/workflows/dotnet.yml)
+
+## SonarCloud Analysis Results
+
+[](https://sonarcloud.io/summary/new_code?id=jbarden_astar-dev-admin-api-client-sdk)
+
+[](https://sonarcloud.io/summary/new_code?id=jbarden_astar-dev-admin-api-client-sdk)
+
+[](https://sonarcloud.io/summary/new_code?id=jbarden_astar-dev-admin-api-client-sdk)
+
+[](https://sonarcloud.io/summary/new_code?id=jbarden_astar-dev-admin-api-client-sdk)
+
+[](https://sonarcloud.io/summary/new_code?id=jbarden_astar-dev-admin-api-client-sdk)
+
+[](https://sonarcloud.io/summary/new_code?id=jbarden_astar-dev-admin-api-client-sdk)
+
diff --git a/src/AStar.Dev.Admin.Api.Client.Sdk/ServiceCollectionExtensions.cs b/src/AStar.Dev.Admin.Api.Client.Sdk/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000..a8a08d9
--- /dev/null
+++ b/src/AStar.Dev.Admin.Api.Client.Sdk/ServiceCollectionExtensions.cs
@@ -0,0 +1,45 @@
+using System.Net.Mime;
+using AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+using AStar.Dev.Api.HealthChecks;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Microsoft.Identity.Web;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk;
+
+///
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddAdminApiClient(this IServiceCollection services, IConfiguration configuration)
+ {
+ var configurationSection = configuration.GetSection(AdminApiConfiguration.SectionLocation);
+
+ _ = services.AddOptions()
+ .Bind(configurationSection)
+ .ValidateDataAnnotations()
+ .ValidateOnStart();
+
+ _ = services.AddScoped();
+
+ _ = services.AddHttpClient()
+ .ConfigureHttpClient((serviceProvider, client) =>
+ {
+ client.BaseAddress = serviceProvider
+ .GetRequiredService>().Value
+ .BaseUrl;
+
+ client.DefaultRequestHeaders.Accept.Add(new(MediaTypeNames.Application.Json));
+ });
+
+ // _ = services.AddDownstreamApi(nameof(AdminApiClient), configuration.GetSection(AdminApiConfiguration.SectionLocation));
+
+ return services;
+ }
+}
\ No newline at end of file
diff --git a/src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj b/src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj
deleted file mode 100644
index 125f4c9..0000000
--- a/src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- net9.0
- enable
- enable
-
-
-
diff --git a/src/AStar.Dev.Example.ClassLib/Class1.cs b/src/AStar.Dev.Example.ClassLib/Class1.cs
deleted file mode 100644
index 27e9361..0000000
--- a/src/AStar.Dev.Example.ClassLib/Class1.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace AStar.Dev.Example.ClassLib;
-
-public class Class1
-{
-
-}
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit.csproj b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit.csproj
new file mode 100644
index 0000000..7ef1293
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit.csproj
@@ -0,0 +1,58 @@
+
+
+
+ net9.0
+ enable
+ enable
+ false
+ AStar.Dev.Admin.Api.Client.Sdk
+ True
+ latest-recommended
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+ True
+ 1701;1702;IDE0058;
+
+
+
+ True
+ 1701;1702;IDE0058;
+
+
+
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetModelToIgnoreShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetModelToIgnoreShould.cs
new file mode 100644
index 0000000..df5a011
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetModelToIgnoreShould.cs
@@ -0,0 +1,41 @@
+using AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiClient))]
+public class AdminApiClientGetModelToIgnoreShould
+{
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetModelsToIgnoreAsyncWhenTheApiIsUnreachable()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetModelsToIgnoreAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureMessageFromGetModelsToIgnoreAsyncWhenCheckFails()
+ {
+ var sut = AdminApiClientFactory.CreateInternalServerErrorClient("ModelsToIgnore");
+
+ var response = await sut.GetModelsToIgnoreAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedMessageFromGetModelsToIgnoreAsyncWhenCheckSucceeds()
+ {
+ var handler = new MockSuccessHttpMessageHandler("ModelsToIgnore");
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetModelsToIgnoreAsync();
+
+ response.IsSuccess.ShouldBeTrue();
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetScrapeDirectoriesShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetScrapeDirectoriesShould.cs
new file mode 100644
index 0000000..5995e63
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetScrapeDirectoriesShould.cs
@@ -0,0 +1,41 @@
+using AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiClient))]
+public class AdminApiClientGetScrapeDirectoriesShould
+{
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetScrapeDirectoriesAsyncWhenTheApiIsUnreachable()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetScrapeDirectoriesAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureMessageFromGetScrapeDirectoriesAsyncWhenCheckFails()
+ {
+ var sut = AdminApiClientFactory.CreateInternalServerErrorClient("ScrapeDirectories");
+
+ var response = await sut.GetScrapeDirectoriesAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedMessageFromGetScrapeDirectoriesAsyncWhenCheckSucceeds()
+ {
+ var handler = new MockSuccessHttpMessageHandler("ScrapeDirectories");
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetScrapeDirectoriesAsync();
+
+ response.IsSuccess.ShouldBeTrue();
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetSearchConfigurationShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetSearchConfigurationShould.cs
new file mode 100644
index 0000000..12c8546
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetSearchConfigurationShould.cs
@@ -0,0 +1,41 @@
+using AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiClient))]
+public class AdminApiClientSearchConfigurationShould
+{
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetSearchConfigurationAsyncWhenTheApiIsUnreachable()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetSearchConfigurationAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureMessageFromGetSearchConfigurationAsyncWhenCheckFails()
+ {
+ var sut = AdminApiClientFactory.CreateInternalServerErrorClient("SearchConfiguration");
+
+ var response = await sut.GetSearchConfigurationAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedMessageFromGetSearchConfigurationAsyncWhenCheckSucceeds()
+ {
+ var handler = new MockSuccessHttpMessageHandler("SearchConfigurations");
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetSearchConfigurationAsync();
+
+ response.IsSuccess.ShouldBeTrue();
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetSiteConfigurationShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetSiteConfigurationShould.cs
new file mode 100644
index 0000000..834c5d6
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientGetSiteConfigurationShould.cs
@@ -0,0 +1,41 @@
+using AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiClient))]
+public class AdminApiClientGetSiteConfigurationShould
+{
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetSiteConfigurationAsyncWhenTheApiIsUnreachable()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetSiteConfigurationAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureMessageFromGetSiteConfigurationAsyncWhenCheckFails()
+ {
+ var sut = AdminApiClientFactory.CreateInternalServerErrorClient("SiteConfiguration");
+
+ var response = await sut.GetSiteConfigurationAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedMessageFromGetSiteConfigurationAsyncWhenCheckSucceeds()
+ {
+ var handler = new MockSuccessHttpMessageHandler("SiteConfigurations");
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetSiteConfigurationAsync();
+
+ response.IsSuccess.ShouldBeTrue();
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientHealthChecksShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientHealthChecksShould.cs
new file mode 100644
index 0000000..0a761fd
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientHealthChecksShould.cs
@@ -0,0 +1,54 @@
+using AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiClient))]
+public class AdminApiClientHealthChecksShould
+{
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetHealthAsyncWhenTheApiIsUnreachableVersion2()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetHealthCheckAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ response.Value?.Description.ShouldBe("Unable to retrieve the description of the Health Status");
+ response.Value?.Status.ShouldBe("Could not get a response from the AStar.Dev.Admin.Api.");
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetHealthAsyncWhenTheApiIsUnreachable()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetHealthAsync();
+
+ response.Status.ShouldBe("Could not get a response from the AStar.Dev.Admin.Api.");
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureMessageFromGetHealthAsyncWhenCheckFails()
+ {
+ var sut = AdminApiClientFactory.CreateInternalServerErrorClient("Health Check failed.");
+
+ var response = await sut.GetHealthAsync();
+
+ response.Status.ShouldBe("Health Check failed - Internal Server Error.");
+ }
+
+ [Fact]
+ public async Task ReturnExpectedMessageFromGetHealthAsyncWhenCheckSucceeds()
+ {
+ var handler = new MockSuccessHttpMessageHandler("Health");
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetHealthAsync();
+
+ response.Status.ShouldBe("OK");
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientTagsToIgnoreShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientTagsToIgnoreShould.cs
new file mode 100644
index 0000000..ee70c13
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiClientTagsToIgnoreShould.cs
@@ -0,0 +1,41 @@
+using AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiClient))]
+public class AdminApiClientTagsToIgnoreShould
+{
+ [Fact]
+ public async Task ReturnExpectedFailureFromGetTagsToIgnoreAsyncWhenTheApiIsUnreachable()
+ {
+ var handler = new MockHttpRequestExceptionErrorHttpMessageHandler();
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetTagsToIgnoreAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedFailureMessageFromGetTagsToIgnoreAsyncWhenCheckFails()
+ {
+ var sut = AdminApiClientFactory.CreateInternalServerErrorClient("tags-to-ignore");
+
+ var response = await sut.GetTagsToIgnoreAsync();
+
+ response.IsFailure.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task ReturnExpectedMessageFromGetTagsToIgnoreAsyncWhenCheckSucceeds()
+ {
+ var handler = new MockSuccessHttpMessageHandler("TagToIgnore");
+ var sut = AdminApiClientFactory.Create(handler);
+
+ var response = await sut.GetTagsToIgnoreAsync();
+
+ response.IsSuccess.ShouldBeTrue();
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiConfigurationShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiConfigurationShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..b88b0fc
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiConfigurationShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,6 @@
+{
+ "baseUrl": "https://www.example.com",
+ "scopes": [
+ "Not Relevant Here"
+ ]
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiConfigurationShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiConfigurationShould.cs
new file mode 100644
index 0000000..eca381e
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/AdminApi/AdminApiConfigurationShould.cs
@@ -0,0 +1,12 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+
+[TestSubject(typeof(AdminApiConfiguration))]
+public class AdminApiConfigurationShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new AdminApiConfiguration { Scopes = ["Not Relevant Here"], BaseUrl = new ("https://www.example.com") }.ToJson().ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/ConstantsShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/ConstantsShould.cs
new file mode 100644
index 0000000..d4def37
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/ConstantsShould.cs
@@ -0,0 +1,12 @@
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk;
+
+[TestSubject(typeof(Constants))]
+public class ConstantsShould
+{
+ [Fact]
+ public void METHOD()
+ {
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Helpers/AdminApiClientFactory.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Helpers/AdminApiClientFactory.cs
new file mode 100644
index 0000000..9ab37d7
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Helpers/AdminApiClientFactory.cs
@@ -0,0 +1,30 @@
+using AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+using AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+using AStar.Dev.Logging.Extensions;
+using Microsoft.Identity.Web;
+using NSubstitute;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Helpers;
+
+internal static class AdminApiClientFactory
+{
+ private const string IrrelevantUrl = "https://doesnot.matter.com";
+ private static readonly ILoggerAstar DummyLogger = Substitute.For>();
+
+ public static AdminApiClient Create(HttpMessageHandler mockHttpMessageHandler)
+ {
+ var tokenAcquisitionServiceMock = Substitute.For();
+ var httpClient = new HttpClient(mockHttpMessageHandler) { BaseAddress = new(IrrelevantUrl) };
+
+ return new(httpClient, tokenAcquisitionServiceMock, DummyLogger);
+ }
+
+ public static AdminApiClient CreateInternalServerErrorClient(string errorMessage)
+ {
+ var tokenAcquisitionServiceMock = Substitute.For();
+ var handler = new MockInternalServerErrorHttpMessageHandler(errorMessage);
+ var httpClient = new HttpClient(handler) { BaseAddress = new(IrrelevantUrl) };
+
+ return new(httpClient, tokenAcquisitionServiceMock, DummyLogger);
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockDeletionSuccessHttpMessageHandler.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockDeletionSuccessHttpMessageHandler.cs
new file mode 100644
index 0000000..6763575
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockDeletionSuccessHttpMessageHandler.cs
@@ -0,0 +1,9 @@
+using System.Net;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+
+public sealed class MockDeletionSuccessHttpMessageHandler : HttpMessageHandler
+{
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Marked for deletion.") });
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockHttpRequestExceptionErrorHttpMessageHandler.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockHttpRequestExceptionErrorHttpMessageHandler.cs
new file mode 100644
index 0000000..c95a8e3
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockHttpRequestExceptionErrorHttpMessageHandler.cs
@@ -0,0 +1,7 @@
+namespace AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+
+public sealed class MockHttpRequestExceptionErrorHttpMessageHandler : HttpMessageHandler
+{
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ => throw new HttpRequestException();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockInternalServerErrorHttpMessageHandler.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockInternalServerErrorHttpMessageHandler.cs
new file mode 100644
index 0000000..f991fc0
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockInternalServerErrorHttpMessageHandler.cs
@@ -0,0 +1,9 @@
+using System.Net;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+
+public sealed class MockInternalServerErrorHttpMessageHandler(string errorMessage) : HttpMessageHandler
+{
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ => Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(errorMessage) });
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockSuccessHttpMessageHandler.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockSuccessHttpMessageHandler.cs
new file mode 100644
index 0000000..6dcb797
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockSuccessHttpMessageHandler.cs
@@ -0,0 +1,49 @@
+using System.Net;
+using System.Text.Json;
+using AStar.Dev.Admin.Api.Client.Sdk.Models;
+using AStar.Dev.Api.HealthChecks;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+
+public sealed class MockSuccessHttpMessageHandler(string responseRequired) : HttpMessageHandler
+{
+ public int Counter { get; set; }
+
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ HttpContent content;
+
+#pragma warning disable IDE0045 // Convert to conditional expression
+ if(responseRequired == "SiteConfigurations")
+ {
+ content = new StringContent(JsonSerializer.Serialize(new List { new () } ));
+ }
+ else if(responseRequired == "SiteConfiguration")
+ {
+ content = new StringContent(JsonSerializer.Serialize(new SiteConfiguration()));
+ }
+ else if(responseRequired == "SearchConfiguration")
+ {
+ content = new StringContent(JsonSerializer.Serialize(new List { new () } ));
+ }
+ else if(responseRequired == "TagToIgnore")
+ {
+ content = new StringContent(JsonSerializer.Serialize(new List { new () } ));
+ }
+ else if(responseRequired == "ModelsToIgnore")
+ {
+ content = new StringContent(JsonSerializer.Serialize(new List { new () } ));
+ }
+ else if (responseRequired == "Health")
+ {
+ content = new StringContent(JsonSerializer.Serialize(new HealthStatusResponse { Status = "OK" }));
+ }
+ else
+ {
+ content = new StringContent(JsonSerializer.Serialize(new HealthStatusResponse { Status = "NotSureYet" }));
+ }
+#pragma warning restore IDE0045 // Convert to conditional expression
+
+ return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = content });
+ }
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockSuccessMessageWithValue0HttpMessageHandler.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockSuccessMessageWithValue0HttpMessageHandler.cs
new file mode 100644
index 0000000..9246885
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/MockMessageHandlers/MockSuccessMessageWithValue0HttpMessageHandler.cs
@@ -0,0 +1,10 @@
+using System.Net;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.MockMessageHandlers;
+
+public sealed class MockSuccessMessageWithValue0HttpMessageHandler : HttpMessageHandler
+{
+ protected override Task SendAsync(HttpRequestMessage request,
+ CancellationToken cancellationToken)
+ => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("0") });
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ModelToIgnoreShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ModelToIgnoreShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..90f112b
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ModelToIgnoreShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,3 @@
+{
+ "value": "Not Relevant Here"
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ModelToIgnoreShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ModelToIgnoreShould.cs
new file mode 100644
index 0000000..ce30d3f
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ModelToIgnoreShould.cs
@@ -0,0 +1,12 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+[TestSubject(typeof(ModelToIgnore))]
+public class ModelToIgnoreShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new ModelToIgnore { Value = "Not Relevant Here" }.ToJson().ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ScrapeDirectoriesShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ScrapeDirectoriesShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..c97e70e
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ScrapeDirectoriesShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,8 @@
+{
+ "id": 1,
+ "rootDirectory": "Root Directory Not Relevant Here",
+ "baseSaveDirectory": "Base Save Directory Not Relevant Here",
+ "baseDirectory": "Base Directory Not Relevant Here",
+ "baseDirectoryFamous": "Base Directory Famous Not Relevant Here",
+ "subDirectoryName": "Sub Directory Not Relevant Here"
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ScrapeDirectoriesShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ScrapeDirectoriesShould.cs
new file mode 100644
index 0000000..7705ce3
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/ScrapeDirectoriesShould.cs
@@ -0,0 +1,22 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+[TestSubject(typeof(ScrapeDirectories))]
+public class ScrapeDirectoriesShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new ScrapeDirectories
+ {
+ BaseSaveDirectory = "Base Save Directory Not Relevant Here",
+ Id = 1,
+ BaseDirectory = "Base Directory Not Relevant Here",
+ SubDirectoryName = "Sub Directory Not Relevant Here",
+ BaseDirectoryFamous = "Base Directory Famous Not Relevant Here",
+ RootDirectory = "Root Directory Not Relevant Here"
+ }
+ .ToJson()
+ .ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchCategoryShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchCategoryShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..b898cc1
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchCategoryShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,8 @@
+{
+ "id": "1",
+ "order": 3,
+ "name": "Name Not Relevant Here",
+ "lastKnownImageCount": 1,
+ "lastPageVisited": 2,
+ "totalPages": 4
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchCategoryShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchCategoryShould.cs
new file mode 100644
index 0000000..6f60312
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchCategoryShould.cs
@@ -0,0 +1,20 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+[TestSubject(typeof(SearchCategory))]
+public class SearchCategoryShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new SearchCategory
+ {
+ Id = "1",
+ Name = "Name Not Relevant Here",
+ LastKnownImageCount = 1,
+ LastPageVisited = 2,
+ Order = 3,
+ TotalPages = 4
+ }.ToJson().ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchConfigurationShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchConfigurationShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..a41daa3
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchConfigurationShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,28 @@
+{
+ "id": 1,
+ "baseUrl": "https://not.relevant.here",
+ "loginUrl": "/not/relevant/here",
+ "searchCategories": [
+ {
+ "id": "111",
+ "order": 2,
+ "name": "Name NotRelevant Here",
+ "lastKnownImageCount": 8,
+ "lastPageVisited": 9,
+ "totalPages": 7
+ }
+ ],
+ "searchString": "",
+ "topWallpapers": "",
+ "searchStringPrefix": "",
+ "searchStringSuffix": "",
+ "subscriptions": "",
+ "imagePauseInSeconds": 5,
+ "startingPageNumber": 0,
+ "totalPages": 9,
+ "useHeadless": false,
+ "subscriptionsStartingPageNumber": 0,
+ "subscriptionsTotalPages": 0,
+ "topWallpapersTotalPages": 0,
+ "topWallpapersStartingPageNumber": 0
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchConfigurationShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchConfigurationShould.cs
new file mode 100644
index 0000000..7113966
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SearchConfigurationShould.cs
@@ -0,0 +1,33 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+[TestSubject(typeof(SearchConfiguration))]
+public class SearchConfigurationShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new SearchConfiguration
+ {
+ BaseUrl = "https://not.relevant.here",
+ TotalPages = 9,
+ Id = 1,
+ ImagePauseInSeconds = 5,
+ LoginUrl = "/not/relevant/here",
+ SearchCategories =
+ [
+ new()
+ {
+ Id = "111",
+ TotalPages = 7,
+ LastKnownImageCount = 8,
+ LastPageVisited = 9,
+ Name = "Name NotRelevant Here",
+ Order = 2
+ }
+ ]
+ }
+ .ToJson()
+ .ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SiteConfigurationShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SiteConfigurationShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..c561002
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SiteConfigurationShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,9 @@
+{
+ "id": 1,
+ "loginEmailAddress": "not@relevant.com",
+ "username": "username not relevant here",
+ "password": "Nope, not this!",
+ "siteConfigurationSlug": "slug-not-relevant-here",
+ "baseUrl": "https://not.relevant.here",
+ "loginUrl": "/login/not/relevant/here"
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SiteConfigurationShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SiteConfigurationShould.cs
new file mode 100644
index 0000000..34c7d81
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/SiteConfigurationShould.cs
@@ -0,0 +1,23 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+[TestSubject(typeof(SiteConfiguration))]
+public class SiteConfigurationShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new SiteConfiguration
+ {
+ BaseUrl = "https://not.relevant.here",
+ Id = 1,
+ LoginUrl = "/login/not/relevant/here",
+ LoginEmailAddress = "not@relevant.com",
+ Password = "Nope, not this!",
+ SiteConfigurationSlug = "slug-not-relevant-here",
+ Username = "username not relevant here"
+ }
+ .ToJson()
+ .ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/TagToIgnoreShould.ContainTheExpectedProperties.approved.txt b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/TagToIgnoreShould.ContainTheExpectedProperties.approved.txt
new file mode 100644
index 0000000..17d8671
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/TagToIgnoreShould.ContainTheExpectedProperties.approved.txt
@@ -0,0 +1,4 @@
+{
+ "value": "Value not relevant here",
+ "ignoreImage": true
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/TagToIgnoreShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/TagToIgnoreShould.cs
new file mode 100644
index 0000000..3c61a75
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/Models/TagToIgnoreShould.cs
@@ -0,0 +1,12 @@
+using AStar.Dev.Utilities;
+using JetBrains.Annotations;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk.Models;
+
+[TestSubject(typeof(TagToIgnore))]
+public class TagToIgnoreShould
+{
+ [Fact]
+ public void ContainTheExpectedProperties()
+ => new TagToIgnore { Value = "Value not relevant here", IgnoreImage = true }.ToJson().ShouldMatchApproved();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/ServiceCollectionExtensionsShould.cs b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/ServiceCollectionExtensionsShould.cs
new file mode 100644
index 0000000..a529170
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/ServiceCollectionExtensionsShould.cs
@@ -0,0 +1,44 @@
+using AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
+using AStar.Dev.Logging.Extensions;
+using JetBrains.Annotations;
+using Microsoft.ApplicationInsights.Channel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Microsoft.Identity.Web;
+using NSubstitute;
+
+namespace AStar.Dev.Admin.Api.Client.Sdk;
+
+[TestSubject(typeof(ServiceCollectionExtensions))]
+public class ServiceCollectionExtensionsShould
+{
+ private readonly ServiceProvider serviceProvider;
+
+ public ServiceCollectionExtensionsShould()
+ {
+ var configurationManager = new ConfigurationManager();
+ configurationManager.AddJsonFile("appsettings.json");
+ var serviceCollection = new ServiceCollection();
+ var tokenAcquisitionServiceMock = Substitute.For();
+ serviceCollection.AddSingleton(tokenAcquisitionServiceMock);
+ var loggerMock = Substitute.For>();
+ serviceCollection.AddSingleton(loggerMock);
+
+ serviceCollection.AddAdminApiClient(configurationManager);
+
+ serviceProvider = serviceCollection.BuildServiceProvider();
+ }
+ [Fact]
+ public void AddTheExpectedServices()
+ {
+ serviceProvider.GetService>().ShouldNotBeNull();
+ serviceProvider.GetService().ShouldNotBeNull();
+ }
+
+ [Fact]
+ public void AddTheExpectedHttpClient()
+ => serviceProvider.GetService().ShouldNotBeNull();
+}
\ No newline at end of file
diff --git a/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/appsettings.json b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/appsettings.json
new file mode 100644
index 0000000..ba47ed0
--- /dev/null
+++ b/test/AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit/appsettings.json
@@ -0,0 +1,74 @@
+{
+ "DetailedErrors": true,
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "apiUsageConfiguration": {
+ "hostName": "astar-api-usage",
+ "userName": "user",
+ "password": null,
+ "queueName": "usage"
+ },
+ "AllowedHosts": "*",
+ "AzureAd": {
+ "Instance": "https://login.microsoftonline.com/",
+ "Domain": "jasonbardenoutlook.onmicrosoft.com",
+ "TenantId": "bb7d94aa-36a9-4a59-a0c1-54a757c47ddf",
+ "ClientId": "2ca26585-5929-4aae-86a7-a00c3fc2d061",
+ "ClientSecret": "This is a secret... LOL",
+ "CallbackPath": "/signin-oidc"
+ },
+ "TodoList": {
+ "Scopes": [
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Read",
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"
+ ],
+ "BaseUrl": "http://todolistservice/",
+ "RelativePath": "api/todolist"
+ },
+ "GraphApi": {
+ "BaseUrl": "https://graph.microsoft.com/v1.0/me",
+ "Scopes": [
+ "user.read"
+ ]
+ },
+ "apiConfiguration": {
+ "adminApiConfiguration": {
+ "Scopes": [
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Read",
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"
+ ],
+ "baseUrl": "http://astar.dev.admin.api/"
+ },
+ "filesApiConfiguration": {
+ "Scopes": [
+ "api://54861ab2-fdb0-4e18-a073-c90e7bf9f0c5/ToDoList.Write",
+ "api://54861ab2-fdb0-4e18-a073-c90e7bf9f0c5/ToDoList.Read"
+ ],
+ "baseUrl": "http://astar.dev.files.api/"
+ },
+ "imagesApiConfiguration": {
+ "Scopes": [
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Read",
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"
+ ],
+ "baseUrl": "http://host.docker.internal:5062/"
+ },
+ "usageApiConfiguration": {
+ "Scopes": [
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Read",
+ "api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"
+ ],
+ "baseUrl": "http://astar.dev.usage.logger/"
+ }
+ },
+ "applicationConfiguration": {
+ "paginationPageDefaultPreAndPostCount": 5
+ },
+ "ApplicationInsights": {
+ "ConnectionString": "InstrumentationKey=Update"
+ }
+}
diff --git a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj b/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj
deleted file mode 100644
index 6fbda4a..0000000
--- a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/UnitTest1.cs b/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/UnitTest1.cs
deleted file mode 100644
index 3928e91..0000000
--- a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/UnitTest1.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace AStar.Dev.Example.ClassLib.Tests.Unit;
-
-public class UnitTest1
-{
- [Fact]
- public void Test1()
- {
-
- }
-}