From ece3695dcafdb4d4d454dd6758b6118b337fb261 Mon Sep 17 00:00:00 2001 From: Steffen Froehlich Date: Fri, 28 Jun 2024 11:14:29 -0700 Subject: [PATCH] Release 4.1.0 --- .config/dotnet-tools.json | 2 +- .github/workflows/dotnet-test.yml | 8 +- .github/workflows/publishdocs-dryrun.yml | 2 +- .github/workflows/publishdocs.yml | 2 +- .github/workflows/python-package.yml | 2 +- .github/workflows/python-test.yml | 2 +- Directory.Build.props | 2 +- Migration SDK.sln | 2 + README.md | 6 +- .../Csharp.ExampleApplication.csproj | 2 +- .../Transformers/EncryptExtractTransformer.cs | 2 +- .../Transformers/MigratedTagTransformer.cs | 2 +- .../MyMigrationApplication.cs | 6 + examples/Csharp.ExampleApplication/Program.cs | 4 + .../appsettings.json | 4 + .../Hooks/mappings/email_domain_mapping.py | 2 +- .../Python.ExampleApplication.pyproj | 1 + .../requirements.txt | 11 +- global.json | 2 +- scripts/generate-docs.ps1 | 10 +- src/Documentation/.gitignore | 1 - src/Documentation/README.md | 4 +- src/Documentation/api-csharp/index.md | 14 +- src/Documentation/api-python/index.md | 2 +- src/Documentation/articles/configuration.md | 12 +- .../articles/hooks/custom_hooks.md | 28 +-- .../articles/hooks/example_hook_use_cases.md | 26 +-- src/Documentation/articles/hooks/index.md | 5 +- src/Documentation/articles/intro.md | 5 - src/Documentation/articles/toc.yml | 2 - src/Documentation/docfx.json | 9 +- src/Documentation/images/configuration.png | Bin 46889 -> 0 bytes src/Documentation/images/hooks.png | Bin 487916 -> 0 bytes src/Documentation/index.md | 20 +- .../batch-migration-completed/intro.md | 7 - .../log_migration_batches.md | 4 +- .../samples/bulk-post-publish/bulk_logging.md | 4 +- .../samples/bulk-post-publish/intro.md | 7 - .../filters/filter_projects_by_name.md | 4 +- .../filters/filter_users_by_site_role.md | 4 +- src/Documentation/samples/filters/intro.md | 12 - src/Documentation/samples/intro.md | 48 ---- .../samples/mappings/change_projects.md | 4 +- src/Documentation/samples/mappings/intro.md | 12 - .../samples/mappings/rename_projects.md | 4 +- .../mappings/username_email_mapping.md | 12 +- .../migration-action-completed/intro.md | 7 - .../log_migration_actions.md | 4 +- .../samples/post-publish/intro.md | 7 - src/Documentation/samples/toc.yml | 16 +- .../encrypt_extracts_transformer.md | 4 +- .../samples/transformers/intro.md | 8 - .../transformers/migrated_tag_transformer.md | 4 +- .../samples/transformers/toc.yml | 2 + .../templates/tableau/styles/main.css | 166 +++++++++++++- src/Documentation/toc.yml | 14 +- src/Python/CONTRIBUTING.md | 12 +- src/Python/Python.pyproj | 10 + src/Python/pyproject.toml | 15 +- src/Python/requirements.txt | 4 +- src/Python/scripts/build_binaries.py | 7 +- src/Python/scripts/publish-package.ps1 | 9 +- src/Python/src/tableau_migration/__init__.py | 11 + src/Python/src/tableau_migration/migration.py | 10 +- .../tableau_migration/migration_content.py | 3 +- .../migration_engine_endpoints_search.py | 4 +- .../migration_engine_migrators.py | 2 +- src/Python/tests/test_classes.py | 47 +++- src/Python/tests/test_migration.py | 104 +++++++++ src/Python/tests/test_migration_content.py | 1 + .../test_migration_content_permissions.py | 15 ++ .../ConversionMode.cs | 4 +- .../Generators/PythonMemberGenerator.cs | 12 +- .../Keywords/Dotnet/Types.cs | 1 + .../Keywords/Python/Modules.cs | 1 + .../Keywords/Python/Types.cs | 1 + .../PythonGenerationList.cs | 101 +++++++- .../PythonTypeReference.cs | 2 +- .../Tableau.Migration.PythonGenerator.csproj | 4 +- .../Writers/PythonConstructorTestWriter.cs | 16 +- .../Writers/PythonMemberWriter.cs | 18 ++ .../Writers/PythonPropertyTestWriter.cs | 157 ++++++------- .../Writers/PythonPropertyWriter.cs | 6 + .../Writers/PythonTestWriter.cs | 80 +++---- src/Tableau.Migration/Api/ApiClient.cs | 47 +++- src/Tableau.Migration/Api/ApiClientBase.cs | 27 +++ .../Api/DataSourcesApiClient.cs | 1 - src/Tableau.Migration/Api/IApiClient.cs | 6 +- src/Tableau.Migration/Api/IApiPageAccessor.cs | 2 +- .../Api/IAuthenticationTokenProvider.cs | 8 +- .../Api/IBatchPublishApiClient.cs | 2 +- .../Api/IConnectionManager.cs | 2 +- .../Api/IContentFileStoreExtensions.cs | 2 +- ...ContentReferenceFinderFactoryExtensions.cs | 36 ++- .../Api/IDataSourcesApiClient.cs | 10 +- src/Tableau.Migration/Api/IGroupsApiClient.cs | 16 +- src/Tableau.Migration/Api/IJobsApiClient.cs | 14 +- .../Api/IOwnershipApiClient.cs | 2 +- .../Api/IPagedListApiClient.cs | 2 +- .../Api/IProjectsApiClient.cs | 10 +- .../Api/IPublishApiClient.cs | 2 +- src/Tableau.Migration/Api/IPullApiClient.cs | 2 +- src/Tableau.Migration/Api/IReadApiClient.cs | 2 +- .../Api/IServerSessionProvider.cs | 19 +- .../Api/IServiceCollectionExtensions.cs | 12 + src/Tableau.Migration/Api/ISitesApiClient.cs | 23 +- src/Tableau.Migration/Api/IUsersApiClient.cs | 12 +- .../Api/IWorkbooksApiClient.cs | 10 +- src/Tableau.Migration/Api/JobsApiClient.cs | 1 - .../Api/Labels/LabelsApiClient.cs | 38 ++- .../DefaultPermissionsApiClient.cs | 69 ++---- .../IDefaultPermissionsApiClient.cs | 14 +- .../Api/Permissions/IPermissionsApiClient.cs | 10 +- .../Api/Permissions/PermissionsApiClient.cs | 27 +-- .../Api/ProjectsApiClient.cs | 6 +- .../Api/Publishing/FilePublisherBase.cs | 2 +- .../Api/Publishing/IFilePublisher.cs | 2 +- .../Rest/Models/ITableauServerListResponse.cs | 4 +- .../Api/Rest/Models/ITableauServerResponse.cs | 13 +- .../Api/Rest/Models/IWithWorkbookType.cs | 30 --- .../Api/Rest/Models/IWorkbookReferenceType.cs | 25 -- .../Models/Requests/PermissionsAddRequest.cs | 1 - .../Models/Responses/PermissionsResponse.cs | 1 - .../Models/Responses/TableauServerResponse.cs | 6 +- .../Api/Rest/Models/Responses/ViewResponse.cs | 4 +- .../Rest/Models/Types/ParentContentType.cs | 1 - .../Api/Rest/Models/Types/PermissionsType.cs | 1 - .../Api/Rest/RestUrlPrefixes.cs | 4 + .../Search/BulkApiContentReferenceCache.cs | 8 +- .../Api/ServerSessionProvider.cs | 27 ++- .../Simulation/ITableauApiSimulatorFactory.cs | 5 +- .../Api/Simulation/Rest/RestApiSimulator.cs | 21 ++ .../Api/Simulation/TableauApiSimulator.cs | 10 +- .../Simulation/TableauApiSimulatorFactory.cs | 4 +- .../Api/Simulation/TableauData.cs | 65 ++++++ src/Tableau.Migration/Api/SitesApiClient.cs | 30 ++- .../Api/Tags/ITagsApiClient.cs | 6 +- .../Api/Tags/TagsApiClient.cs | 14 +- src/Tableau.Migration/Api/UsersApiClient.cs | 1 - .../Api/ViewsApiClientFactory.cs | 9 +- .../Api/WorkbooksApiClient.cs | 1 - src/Tableau.Migration/ComparerBase.cs | 30 +++ src/Tableau.Migration/Constants.cs | 8 +- .../Content/Files/IContentFileHandle.cs | 4 +- .../Content/Files/IContentFileStore.cs | 14 +- .../Content/Files/ITableauFileXmlStream.cs | 2 +- .../Search/CachedContentReferenceFinder.cs | 19 +- .../Search/ContentReferenceCacheBase.cs | 8 +- .../Content/Search/IContentReferenceCache.cs | 4 +- .../Content/Search/IContentReferenceFinder.cs | 17 +- .../Search/IContentReferenceFinderFactory.cs | 19 ++ .../Engine/Actions/IMigrationAction.cs | 2 +- .../Engine/Endpoints/IDestinationEndpoint.cs | 12 +- .../Engine/Endpoints/IMigrationEndpoint.cs | 4 +- .../Engine/Endpoints/ISourceEndpoint.cs | 6 +- .../Endpoints/Search/ILockedProjectCache.cs | 2 +- .../TableauApiDestinationEndpoint.cs | 2 +- .../Engine/Hooks/Filters/ContentFilterBase.cs | 32 ++- .../Default/UserSiteRoleSupportUserFilter.cs | 1 - .../Hooks/Filters/IContentFilterRunner.cs | 2 +- .../Engine/Hooks/IMigrationHook.cs | 2 +- .../Hooks/Mappings/ContentMappingBase.cs | 32 ++- .../AuthenticationTypeDomainMapping.cs | 2 +- .../AuthenticationTypeDomainMappingBase.cs | 2 +- ...CallbackAuthenticationTypeDomainMapping.cs | 2 +- .../Hooks/Mappings/IContentMappingRunner.cs | 2 +- .../Engine/Hooks/MigrationHookBuilder.cs | 8 +- .../Default/PermissionPostPublishHookBase.cs | 2 +- .../Transformers/ContentTransformerBase.cs | 33 ++- .../Transformers/ContentTransformerBuilder.cs | 2 +- .../Default/GroupUsersTransformer.cs | 11 +- .../Default/MappedUserTransformer.cs | 1 - .../Transformers/IContentTransformerRunner.cs | 2 +- .../Transformers/IXmlContentTransformer.cs | 2 +- .../Engine/IServiceCollectionExtensions.cs | 6 +- .../IMigrationManifestEntryBuilder.cs | 2 +- .../Engine/MigrationPlanBuilder.cs | 9 +- .../Batch/ContentBatchMigratorBase.cs | 2 +- .../Migrators/Batch/IContentBatchMigrator.cs | 2 +- .../Engine/Migrators/IContentMigrator.cs | 2 +- .../Pipelines/IMigrationPipelineRunner.cs | 2 +- .../Engine/Pipelines/MigrationPipelineBase.cs | 5 + .../Pipelines/MigrationPipelineContentType.cs | 36 ++- .../ServerToCloudMigrationPipeline.cs | 7 + .../Preparation/ContentItemPreparerBase.cs | 8 +- src/Tableau.Migration/IContentReference.cs | 9 +- .../IContentReferenceExtensions.cs | 6 - src/Tableau.Migration/IMigrator.cs | 4 +- .../Hooks/Filters/ISyncContentFilter.cs | 43 ---- .../Hooks/Mappings/ISyncContentMapping.cs | 41 ---- .../PostPublish/ISyncBulkPostPublishHook.cs | 40 ---- .../ISyncContentItemPostPublishHook.cs | 41 ---- .../Transformers/ISyncContentTransformer.cs | 40 ---- .../ISyncXmlContentTransformer.cs | 58 ----- .../Interop/InteropHelper.cs | 20 +- src/Tableau.Migration/NameOf.cs | 2 +- .../Net/IHttpStreamProcessor.cs | 2 +- .../Net/Simulation/IResponseSimulator.cs | 2 +- .../Simulation/Responses/IResponseBuilder.cs | 2 +- src/Tableau.Migration/Paging/IPager.cs | 6 +- .../Paging/IndexedPagerBase.cs | 2 +- .../Resources/SharedResourceKeys.cs | 6 + .../Resources/SharedResources.resx | 11 + .../Tableau.Migration.csproj | 10 +- .../Python.TestApplication.pyproj | 1 + tests/Python.TestApplication/main.py | 2 + .../migration_testcomponents_filters.py | 13 ++ tests/Python.TestApplication/pyproject.toml | 9 +- tests/Python.TestApplication/requirements.txt | 6 +- ...ngDestinationUsersFromGroupsTransformer.cs | 4 +- .../Hooks/SkipFilter.cs | 11 +- .../Tableau.Migration.TestApplication.csproj | 11 +- .../TestApplication.cs | 23 +- .../appsettings.json | 6 +- ...leau.Migration.TestComponents.Tests.csproj | 11 +- .../Manifest/MigrationManifestSerializer.cs | 4 +- .../EnumDataAttribute.cs | 13 +- .../Tableau.Migration.Tests/FixtureFactory.cs | 115 ++++++++++ .../IEnumerableExtensions.cs | 24 ++ .../MultiDestinationSimulationTestBase.cs | 4 +- .../ServerToCloudSimulationTestBase.cs | 192 +++++++++++++++- .../ServerToServerSimulationTestBase.cs | 4 +- .../Simulation/SimulationTestBase.cs | 39 +++- .../SingleServerSimulationTestBase.cs | 4 +- .../Simulation/TableauDataExtensions.cs | 216 +++++++++++++++++- .../Simulation/Tests/Api/ApiClientTestBase.cs | 4 +- .../Simulation/Tests/Api/ApiClientTests.cs | 54 +++++ .../Tests/Api/SitesApiClientTests.cs | 61 ++++- .../Tests/WorkbookMigrationTests.cs | 1 - .../Tableau.Migration.Tests.csproj | 15 +- .../TestContentType.cs | 16 +- .../Unit/Api/ApiClientTestDependencies.cs | 18 +- .../Unit/Api/ApiClientTests.cs | 105 +++++++-- .../Unit/Api/ApiTestBase.cs | 66 ++++++ .../Unit/Api/GroupsApiClientTests.cs | 6 +- .../Unit/Api/IApiClientTestDependencies.cs | 8 +- .../Api/IServiceCollectionExtensionsTests.cs | 25 +- .../Unit/Api/ServerSessionProviderTests.cs | 9 +- .../TableauApiSimulatorFactoryTests.cs | 6 +- .../Unit/Api/SitesApiClientTests.cs | 4 +- .../Unit/Config/ConfigurationTests.cs | 9 +- .../Content/Files/ContentFileStreamTests.cs | 4 +- .../Files/SeekableCryptoStreamTests.cs | 2 +- .../Search/BulkDestinationCacheTest.cs | 35 +-- .../BulkDestinationProjectCacheTests.cs | 1 - .../IServiceCollectionExtensionsTests.cs | 8 + .../Unit/Engine/MigrationPlanBuilderTests.cs | 22 +- .../Pipelines/MigrationPipelineBaseTests.cs | 21 ++ .../MigrationPipelineContentTypeTests.cs | 20 +- .../ServerToCloudMigrationPipelineTests.cs | 5 +- .../Hooks/Filters/ISyncContentFilterTests.cs | 56 ----- .../Interop/Hooks/ISyncContentMappingTests.cs | 54 ----- .../Hooks/ISyncContentTransformerTests.cs | 53 ----- .../Mappings/ISyncContentMappingTests.cs | 55 ----- .../ISyncBulkPostPublishHookTests.cs | 55 ----- .../ISyncContentItemPostPublishHookTests.cs | 55 ----- .../ISyncContentTransformerTests.cs | 54 ----- .../ISyncXmlContentTransformerTests.cs | 64 ------ .../Net/HttpContentRequestBuilderTests.cs | 5 +- 259 files changed, 2600 insertions(+), 1747 deletions(-) delete mode 100644 src/Documentation/articles/intro.md delete mode 100644 src/Documentation/images/configuration.png delete mode 100644 src/Documentation/images/hooks.png delete mode 100644 src/Documentation/samples/batch-migration-completed/intro.md delete mode 100644 src/Documentation/samples/bulk-post-publish/intro.md delete mode 100644 src/Documentation/samples/filters/intro.md delete mode 100644 src/Documentation/samples/intro.md delete mode 100644 src/Documentation/samples/mappings/intro.md delete mode 100644 src/Documentation/samples/migration-action-completed/intro.md delete mode 100644 src/Documentation/samples/post-publish/intro.md delete mode 100644 src/Documentation/samples/transformers/intro.md delete mode 100644 src/Tableau.Migration/Api/Rest/Models/IWithWorkbookType.cs delete mode 100644 src/Tableau.Migration/Api/Rest/Models/IWorkbookReferenceType.cs delete mode 100644 src/Tableau.Migration/Interop/Hooks/Filters/ISyncContentFilter.cs delete mode 100644 src/Tableau.Migration/Interop/Hooks/Mappings/ISyncContentMapping.cs delete mode 100644 src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncBulkPostPublishHook.cs delete mode 100644 src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHook.cs delete mode 100644 src/Tableau.Migration/Interop/Hooks/Transformers/ISyncContentTransformer.cs delete mode 100644 src/Tableau.Migration/Interop/Hooks/Transformers/ISyncXmlContentTransformer.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Filters/ISyncContentFilterTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentMappingTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentTransformerTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Mappings/ISyncContentMappingTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncBulkPostPublishHookTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHookTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncContentTransformerTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncXmlContentTransformerTests.cs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 278b6c75..723b0f95 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "docfx": { - "version": "2.75.3", + "version": "2.76.0", "commands": [ "docfx" ] diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml index 6840db6d..29a2f21a 100644 --- a/.github/workflows/dotnet-test.yml +++ b/.github/workflows/dotnet-test.yml @@ -26,7 +26,7 @@ jobs: run: dotnet build '${{ vars.BUILD_SOLUTION }}' -c ${{ matrix.config }} - name: Test solution with ${{ matrix.config }} configuration run: | - dotnet test '${{ vars.BUILD_SOLUTION }}' --no-build -c ${{ matrix.config }} --verbosity normal --logger trx --results-directory "TestResults-${{ matrix.os }}-${{ matrix.config }}" -- RunConfiguration.TestSessionTimeout=${{ vars.MIGRATIONSDK_TEST_CANCELLATION_TIMEOUT_MILLISECONDS }} + dotnet test '${{ vars.BUILD_SOLUTION }}' --no-build -c ${{ matrix.config }} --verbosity normal --logger junit --results-directory "TestResults-${{ matrix.os }}-${{ matrix.config }}" -- RunConfiguration.TestSessionTimeout=${{ vars.MIGRATIONSDK_TEST_CANCELLATION_TIMEOUT_MILLISECONDS }} - name: Upload test results # Use always() to always run this step to publish test results when there are test failures if: ${{ always() }} @@ -35,3 +35,9 @@ jobs: name: dotnet-results-${{ matrix.os }}-${{ matrix.config }} path: TestResults-${{ matrix.os }}-${{ matrix.config }} if-no-files-found: error + - name: Publish Unit Test Results + uses: test-summary/action@v2 + with: + paths: TestResults-${{ matrix.os }}-${{ matrix.config }}/*.xml + show: "fail, skip" + diff --git a/.github/workflows/publishdocs-dryrun.yml b/.github/workflows/publishdocs-dryrun.yml index 773bb81e..77d35191 100644 --- a/.github/workflows/publishdocs-dryrun.yml +++ b/.github/workflows/publishdocs-dryrun.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-dotnet - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ inputs.python-version }} - name: Generate API Reference Docs.. diff --git a/.github/workflows/publishdocs.yml b/.github/workflows/publishdocs.yml index 3ba9c207..f6966427 100644 --- a/.github/workflows/publishdocs.yml +++ b/.github/workflows/publishdocs.yml @@ -37,7 +37,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-dotnet - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ inputs.python-version }} - name: Generate API Reference Docs.. diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 12b6f93f..58fc4cea 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -43,7 +43,7 @@ jobs: - uses: ./.github/actions/setup-dotnet if: ${{ env.PUBLISH_PACKAGE_KEY != '' && inputs.runs-on-config != 'self-hosted' }} - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 if: ${{ env.PUBLISH_PACKAGE_KEY != '' && inputs.runs-on-config != 'self-hosted' }} with: python-version: ${{ vars.PYTHON_TEST_VERSIONS }} diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 36e6e0f3..afd36f95 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-dotnet - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ vars.PYTHON_TEST_VERSIONS }} cache: 'pip' # caching pip dependencies diff --git a/Directory.Build.props b/Directory.Build.props index d009a186..a5c1c23e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ enable true true - 4.0.0 + 4.1.0 Salesforce, Inc. Salesforce, Inc. Copyright (c) 2024, Salesforce, Inc. and its licensors diff --git a/Migration SDK.sln b/Migration SDK.sln index 6ad00fc9..66d20255 100644 --- a/Migration SDK.sln +++ b/Migration SDK.sln @@ -52,6 +52,8 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{92044843-B4D7-4062-B1D5-DE7596072E33}" ProjectSection(SolutionItems) = preProject scripts\generate-docs.ps1 = scripts\generate-docs.ps1 + scripts\sync-release-settings.json = scripts\sync-release-settings.json + scripts\sync-release.ps1 = scripts\sync-release.ps1 EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DependencyInjection.ExampleApplication", "examples\DependencyInjection.ExampleApplication\DependencyInjection.ExampleApplication.csproj", "{99DA12FB-BB16-4EE1-9C9C-047755210255}" diff --git a/README.md b/README.md index ea6f3035..31064e52 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ The Tableau Migration SDK is a client library to build an application to facilit Quickstart: - Install a [.NET Runtime](https://dotnet.microsoft.com/en-us/download). - For Python install using PIP: - - [PIP CLI](https://pip.pypa.io/en/stable/cli/pip_install): `pip install tableau-migration` + - [PIP CLI](https://pip.pypa.io/en/stable/cli/pip_install): `pip install tableau_migration` - For C# install using NuGet: - - [dotnet CLI](https://learn.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-using-the-dotnet-cli): `dotnet add package Tableau.Migration --version 1.0.0` + - [dotnet CLI](https://learn.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-using-the-dotnet-cli): `dotnet add package Tableau.Migration` - [Nuget Package Manager](https://learn.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio): Search for `Tableau.Migration`. -- Then check out our [code samples](https://tableau.github.io/migration-sdk/samples/intro.html). +- Then check out our [code samples](https://tableau.github.io/migration-sdk/samples/index.html). To look at source code and delve deeper, first clone the repo: diff --git a/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj b/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj index bb42f3e7..ac6bdc16 100644 --- a/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj +++ b/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj @@ -4,7 +4,7 @@ net6.0;net8.0 CA2007,IDE0073 - 7d7631f1-dc4a-49de-89d5-a194544705c1 + 8368baab-103b-45f6-bfb1-f89a537f4f3c diff --git a/examples/Csharp.ExampleApplication/Hooks/Transformers/EncryptExtractTransformer.cs b/examples/Csharp.ExampleApplication/Hooks/Transformers/EncryptExtractTransformer.cs index 855df7c3..1abd84ab 100644 --- a/examples/Csharp.ExampleApplication/Hooks/Transformers/EncryptExtractTransformer.cs +++ b/examples/Csharp.ExampleApplication/Hooks/Transformers/EncryptExtractTransformer.cs @@ -15,7 +15,7 @@ public class EncryptExtractsTransformer : ContentTransformerBase where T : { private readonly ILogger>? _logger; - public EncryptExtractsTransformer(ISharedResourcesLocalizer? localizer, ILogger>? logger) : base(localizer, logger) + public EncryptExtractsTransformer(ISharedResourcesLocalizer localizer, ILogger> logger) : base(localizer, logger) { _logger = logger; } diff --git a/examples/Csharp.ExampleApplication/Hooks/Transformers/MigratedTagTransformer.cs b/examples/Csharp.ExampleApplication/Hooks/Transformers/MigratedTagTransformer.cs index f48beffa..c629fae6 100644 --- a/examples/Csharp.ExampleApplication/Hooks/Transformers/MigratedTagTransformer.cs +++ b/examples/Csharp.ExampleApplication/Hooks/Transformers/MigratedTagTransformer.cs @@ -15,7 +15,7 @@ public class MigratedTagTransformer : ContentTransformerBase where T : ICo { private readonly ILogger>? _logger; - public MigratedTagTransformer(ISharedResourcesLocalizer? localizer, ILogger>? logger) : base(localizer, logger) + public MigratedTagTransformer(ISharedResourcesLocalizer localizer, ILogger> logger) : base(localizer, logger) { _logger = logger; } diff --git a/examples/Csharp.ExampleApplication/MyMigrationApplication.cs b/examples/Csharp.ExampleApplication/MyMigrationApplication.cs index 1746c79a..840adcd1 100644 --- a/examples/Csharp.ExampleApplication/MyMigrationApplication.cs +++ b/examples/Csharp.ExampleApplication/MyMigrationApplication.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Options; using Tableau.Migration; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules.Cloud; using Tableau.Migration.Engine.Pipelines; #region namespace @@ -120,6 +121,10 @@ public async Task StartAsync(CancellationToken cancel) _planBuilder.Transformers.Add, IPublishableWorkbook>(); #endregion + #region StartAtTransformer-Registration + _planBuilder.Transformers.Add, ICloudExtractRefreshTask>(); + #endregion + // Add migration action completed hooks #region LogMigrationActionsHook-Registration _planBuilder.Hooks.Add(); @@ -131,6 +136,7 @@ public async Task StartAsync(CancellationToken cancel) _planBuilder.Hooks.Add>(); _planBuilder.Hooks.Add>(); _planBuilder.Hooks.Add>(); + _planBuilder.Hooks.Add>(); #endregion // Build the plan diff --git a/examples/Csharp.ExampleApplication/Program.cs b/examples/Csharp.ExampleApplication/Program.cs index e524e057..1b56c72f 100644 --- a/examples/Csharp.ExampleApplication/Program.cs +++ b/examples/Csharp.ExampleApplication/Program.cs @@ -87,6 +87,10 @@ public static IServiceCollection AddCustomizations(this IServiceCollection servi services.AddScoped>(); #endregion + #region StartAtTransformer-DI + services.AddScoped(typeof(SimpleScheduleStartAtTransformer<>)); + #endregion + #region LogMigrationActionsHook-DI services.AddScoped(); #endregion diff --git a/examples/Csharp.ExampleApplication/appsettings.json b/examples/Csharp.ExampleApplication/appsettings.json index b4eb76a7..17d5cd83 100644 --- a/examples/Csharp.ExampleApplication/appsettings.json +++ b/examples/Csharp.ExampleApplication/appsettings.json @@ -32,6 +32,10 @@ { "type": "workbook", "batchSize": 90 + }, + { + "type": "serverextractrefreshtask", + "batchSize": 100 } ] }, diff --git a/examples/Python.ExampleApplication/Hooks/mappings/email_domain_mapping.py b/examples/Python.ExampleApplication/Hooks/mappings/email_domain_mapping.py index 24c3a82e..1618befa 100644 --- a/examples/Python.ExampleApplication/Hooks/mappings/email_domain_mapping.py +++ b/examples/Python.ExampleApplication/Hooks/mappings/email_domain_mapping.py @@ -11,7 +11,7 @@ def map(self, ctx: ContentMappingContext[IUser]) -> ContentMappingContext[IUser] _tableau_user_domain = ctx.mapped_location.parent() # Re-use an existing email if it already exists. - if not ctx.content_item.email: + if ctx.content_item.email: return ctx.map_to(_tableau_user_domain.append(ctx.content_item.email)) # Takes the existing username and appends the domain to build the email diff --git a/examples/Python.ExampleApplication/Python.ExampleApplication.pyproj b/examples/Python.ExampleApplication/Python.ExampleApplication.pyproj index 0af8dedb..f2f9cbec 100644 --- a/examples/Python.ExampleApplication/Python.ExampleApplication.pyproj +++ b/examples/Python.ExampleApplication/Python.ExampleApplication.pyproj @@ -32,6 +32,7 @@ + diff --git a/examples/Python.ExampleApplication/requirements.txt b/examples/Python.ExampleApplication/requirements.txt index ae90bd2c..b93e298a 100644 --- a/examples/Python.ExampleApplication/requirements.txt +++ b/examples/Python.ExampleApplication/requirements.txt @@ -1,10 +1,7 @@ ---index-url https://artifactory.prod.tableautools.com/artifactory/api/pypi/tabpypi/simple ---pre -pip==24.0.0 -setuptools==69.1.0 -configparser==6.0.0 +setuptools==70.1.1 +configparser==7.0.0 tableau_migration cffi==1.16.0 -pycparser==2.21 +pycparser==2.22 pythonnet==3.0.3 -typing_extensions==4.9.0 +typing_extensions==4.12.2 diff --git a/global.json b/global.json index 922949d8..34b2b9f0 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.201", + "version": "8.0.302", "rollForward": "latestMajor" } } \ No newline at end of file diff --git a/scripts/generate-docs.ps1 b/scripts/generate-docs.ps1 index 94d9676f..6093c6c2 100644 --- a/scripts/generate-docs.ps1 +++ b/scripts/generate-docs.ps1 @@ -49,12 +49,12 @@ $main_docs_dir = Join-Path $root_dir "src/Documentation" $sphinx_output_dir = Join-Path $python_dir "Documentation/generated" # Directory for Python wrapper files. Includes an index file and a directory for autogenerated files. -$python_wrapper_dir = Join-Path $main_docs_dir "api-python"; +$python_apiref_dir = Join-Path $main_docs_dir "api-python"; $python_reference_dir_name = "reference"; # Directory where DocFX looks for markdown files to render into our 'Python Wrapper' section. -$python_md_destination = Join-Path $python_wrapper_dir $python_reference_dir_name; +$python_md_destination = Join-Path $python_apiref_dir $python_reference_dir_name; function Run-Command { param([string]$Cmd) @@ -152,7 +152,7 @@ function Write-Python-docs { Run-Command ("python -m pip install -q --upgrade pip"); Run-Command ("python -m pip install -q hatch"); Run-Command ("Clear-Directory -Path $sphinx_output_dir"); - Run-Command ("python -m hatch run docs:sphinx-build -M markdown $sphinx_build_dir $sphinx_output_dir -q"); + Run-Command ("python -m hatch run docs:sphinx-build -M markdown $sphinx_build_dir $sphinx_output_dir -Q"); Run-Command ("Pop-Location"); Write-Host-With-Timestamp "Finished: Generating python docs."; @@ -269,7 +269,7 @@ function Write-Python-Docs-Toc { } } - $tocPath = Join-Path -Path $python_wrapper_dir -ChildPath toc.yml; + $tocPath = Join-Path -Path $python_apiref_dir -ChildPath toc.yml; Run-Command ("Out-File -FilePath '$tocPath' -InputObject '$($fileContent | Out-String)'"); @@ -290,7 +290,7 @@ function Write-Final-Docs { # Docfx related paths $docfx_config_path = Join-Path $main_docs_dir "docfx.json"; - $docfx_cmd = "dotnet docfx $docfx_config_path -t statictoc,templates\tableau --logLevel warning"; + $docfx_cmd = "dotnet docfx $docfx_config_path -t default,statictoc,templates\tableau --logLevel warning"; # Run the docfx command to generate the final output if ($Serve) { diff --git a/src/Documentation/.gitignore b/src/Documentation/.gitignore index d264e89c..3fb2fb82 100644 --- a/src/Documentation/.gitignore +++ b/src/Documentation/.gitignore @@ -6,5 +6,4 @@ /**/packages/ /**/bin/ /**/obj/ -_site migration_sdk_metadata.json diff --git a/src/Documentation/README.md b/src/Documentation/README.md index 1519c0e9..af609f26 100644 --- a/src/Documentation/README.md +++ b/src/Documentation/README.md @@ -148,7 +148,7 @@ Content in Tab 3 ##### Using regions (Preferred method) ```markdown -[!code-csharp[CS](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#DefaultProjectsFilter-Registration)] +[!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#DefaultProjectsFilter-Registration)] ``` ##### Using line numbers @@ -157,7 +157,7 @@ Content in Tab 3 > Use these very sparingly for C#. When the code is edited, it can change line numbers and mess up code snippets. ```markdown -[!code-csharp[CS](../../../../examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMapping.cs#L8-)] +[!code-csharp[](../../../../examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMapping.cs#L8-)] ``` > [!IMPORTANT] diff --git a/src/Documentation/api-csharp/index.md b/src/Documentation/api-csharp/index.md index 14861723..e34a3fe2 100644 --- a/src/Documentation/api-csharp/index.md +++ b/src/Documentation/api-csharp/index.md @@ -4,21 +4,21 @@ Welcome to the C# API Reference for the Migration SDK. ## Examples to get started -The following code samples are for writing a simple migration app using the Migration SDK. For details on configuring and customizing the Migration SDK to your specific needs, see [Articles](~/articles/intro.md) and [Code Samples](~/samples/intro.md). +The following code samples are for writing a simple migration app using the Migration SDK. For details on configuring and customizing the Migration SDK to your specific needs, see [Articles](~/articles/index.md) and [Code Samples](~/samples/index.md). ### [Program.cs](#tab/program-cs) -[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/Program.cs#namespace)] +[!code-csharp[](../../../examples/Csharp.ExampleApplication/Program.cs#namespace)] ### [Startup code](#tab/startup-cde) -[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#namespace)] +[!code-csharp[](../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#namespace)] ### [Config classes](#tab/config-classes) -[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/Config/MyMigrationApplicationOptions.cs#namespace)] +[!code-csharp[](../../../examples/Csharp.ExampleApplication/Config/MyMigrationApplicationOptions.cs#namespace)] -[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/Config/EndpointOptions.cs#namespace)] +[!code-csharp[](../../../examples/Csharp.ExampleApplication/Config/EndpointOptions.cs#namespace)] ### [Config file](#tab/appsettings) @@ -43,5 +43,5 @@ The following code samples are for writing a simple migration app using the Migr ## Suggested Reading -- [Code Samples](~/samples/intro.md) -- [Articles](~/articles/intro.md) +- [Code Samples](~/samples/index.md) +- [Articles](~/articles/index.md) diff --git a/src/Documentation/api-python/index.md b/src/Documentation/api-python/index.md index 5fd176fa..e008e3ac 100644 --- a/src/Documentation/api-python/index.md +++ b/src/Documentation/api-python/index.md @@ -22,7 +22,7 @@ There are advanced features of the Migration SDK that the Python Wrapper cannot ## Examples to get started -The following code samples are for writing a simple migration app using the Migration SDK. For details on configuring and customizing the Migration SDK to your specific needs, see [Articles](~/articles/intro.md) and [Code Samples](~/samples/intro.md). +The following code samples are for writing a simple migration app using the Migration SDK. For details on configuring and customizing the Migration SDK to your specific needs, see [Articles](~/articles/index.md) and [Code Samples](~/samples/index.md). ### [Startup Script](#tab/startup) diff --git a/src/Documentation/articles/configuration.md b/src/Documentation/articles/configuration.md index 6ae668fc..02bd091a 100644 --- a/src/Documentation/articles/configuration.md +++ b/src/Documentation/articles/configuration.md @@ -2,7 +2,7 @@ The Migration SDK uses two sources of configuration in two blocks: the [Migration Plan](#migration-plan) that contains configuration for a specific migration run, and [Migration SDK Options](#migration-sdk-options) for configuration that is unlikely to change between migration runs. -![Configuration Blocks](../images/configuration.png) +![Configuration Blocks](../images/configuration.svg){width=65%} ## Migration Plan @@ -79,7 +79,10 @@ This is an array of [`MigrationSdkOptions.ContentTypesOptions`](xref:Tableau.Mig > The [type](xref:Tableau.Migration.Config.ContentTypesOptions.Type) values are case-insensitive. > Duplicate [type](xref:Tableau.Migration.Config.ContentTypesOptions.Type) key values will result in an exception. -In the following `json` example config file, a `BatchSize` of `201` is applied to the content type `User`. The same setting for `Project` is `203`. +In the following `json` example config file, +- A `BatchSize` of `201` is applied to the content type `User`. +- A `BatchSize` of `203` for `Project`. +- A `BatchSize` of `200` for `ServerExtractRefreshTask`. ```JSON { @@ -92,6 +95,10 @@ In the following `json` example config file, a `BatchSize` of `201` is applied t { "type":"Project", "batchSize": 203 + }, + { + "type":"ServerExtractRefreshTask", + "batchSize": 200 } ], } @@ -146,6 +153,7 @@ The following sections describe each setting. They should always be set per cont *Description:* The Migration SDK uses the **BatchPublishingEnabled** property to select the mode it will publish a given content type. Disabled by default, with this configuration, the SDK will publish the content by using individual REST API calls for each item. When this option is enabled, it is possible to publish content in a batch of items (just for some supported content types). Supported Content Types: + - [User](xref:Tableau.Migration.Content.IUser) by using the method [Import Users to Site from CSV](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#import_users_to_site_from_csv); ### MigrationParallelism diff --git a/src/Documentation/articles/hooks/custom_hooks.md b/src/Documentation/articles/hooks/custom_hooks.md index e79e829e..b400fa23 100644 --- a/src/Documentation/articles/hooks/custom_hooks.md +++ b/src/Documentation/articles/hooks/custom_hooks.md @@ -17,18 +17,18 @@ For example: [`PyContentFilterBase`](~/api-python/reference/tableau_migration.mi | Type | Base Class | Code Samples | |---------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| -| [Filters](~/api-python/reference/tableau_migration.migration_engine_hooks_filters_interop.md) | [`ContentFilterBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_filters_interop.PyContentFilterBase.md) | [Code Samples/Filters](~/samples/filters/intro.md) | -| [Mappings](~/api-python/reference/tableau_migration.migration_engine_hooks_mappings_interop.md) | [`ContentMappingBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_mappings_interop.PyContentMappingBase.md) | [Code Samples/Mappings](~/samples/mappings/intro.md) | -| [Transformers](~/api-python/reference/tableau_migration.migration_engine_hooks_transformers_interop.md) | [`ContentTransformerBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_transformers_interop.PyContentTransformerBase.md) | [Code Samples/Transformers](~/samples/transformers/intro.md) | +| [Filters](~/api-python/reference/tableau_migration.migration_engine_hooks_filters_interop.md) | [`ContentFilterBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_filters_interop.PyContentFilterBase.md) | [Code Samples/Filters](~/samples/filters/index.md) | +| [Mappings](~/api-python/reference/tableau_migration.migration_engine_hooks_mappings_interop.md) | [`ContentMappingBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_mappings_interop.PyContentMappingBase.md) | [Code Samples/Mappings](~/samples/mappings/index.md) | +| [Transformers](~/api-python/reference/tableau_migration.migration_engine_hooks_transformers_interop.md) | [`ContentTransformerBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_transformers_interop.PyContentTransformerBase.md) | [Code Samples/Transformers](~/samples/transformers/index.md) | #### Post-Migration | Type | Base Class | Code Samples | |-------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------| -| [Post-Publish](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.md) | [`ContentItemPostPublishHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.PyBulkPostPublishHookBase.md) | [Code Samples/Post-Publish Hooks](~/samples/post-publish/intro.md) | -| [Bulk Post-Publish](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.md) | [`BulkPostPublishHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.PyBulkPostPublishHookBase.md) | [Code Samples/Bulk Post-Publish](~/samples/bulk-post-publish/intro.md) | -| [Batch Migration Completed](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.md) | [`ContentBatchMigrationCompletedHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.PyContentBatchMigrationCompletedHookBase.md) | [Code Samples/Batch Completed](~/samples/batch-migration-completed/intro.md) | -| [Migration Action Completed](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.md) | [`MigrationActionCompletedHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.PyMigrationActionCompletedHookBase.md) | [Code Samples/Action Completed](~/samples/migration-action-completed/intro.md) | +| [Post-Publish](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.md) | [`ContentItemPostPublishHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.PyBulkPostPublishHookBase.md) | [Code Samples/Post-Publish Hooks](~/samples/post-publish/index.md) | +| [Bulk Post-Publish](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.md) | [`BulkPostPublishHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_postpublish_interop.PyBulkPostPublishHookBase.md) | [Code Samples/Bulk Post-Publish](~/samples/bulk-post-publish/index.md) | +| [Batch Migration Completed](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.md) | [`ContentBatchMigrationCompletedHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.PyContentBatchMigrationCompletedHookBase.md) | [Code Samples/Batch Completed](~/samples/batch-migration-completed/index.md) | +| [Migration Action Completed](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.md) | [`MigrationActionCompletedHookBase`](~/api-python/reference/tableau_migration.migration_engine_hooks_interop.PyMigrationActionCompletedHookBase.md) | [Code Samples/Action Completed](~/samples/migration-action-completed/index.md) | #### Registration @@ -40,18 +40,18 @@ To register Python hooks, register the object with the appropriate hook type lis | Type | Base Class | Interface | Code Samples | |---------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| -| [Filters](xref:Tableau.Migration.Engine.Hooks.Filters) | [`ContentFilterBase`](xref:Tableau.Migration.Engine.Hooks.Filters.ContentFilterBase`1) | [`IContentFilter`](xref:Tableau.Migration.Engine.Hooks.Filters.IContentFilter`1) | [Code Samples/Filters](~/samples/filters/intro.md) | -| [Mappings](xref:Tableau.Migration.Engine.Hooks.Mappings) | [`ContentMappingBase`](xref:Tableau.Migration.Engine.Hooks.Mappings.ContentMappingBase`1) | [`IContentMapping`](xref:Tableau.Migration.Engine.Hooks.Mappings.IContentMapping`1) | [Code Samples/Mappings](~/samples/mappings/intro.md) | -| [Transformers](xref:Tableau.Migration.Engine.Hooks.Transformers) | [`ContentTransformerBase`](xref:Tableau.Migration.Engine.Hooks.Transformers.ContentTransformerBase`1) | [`IContentTransformer`](xref:Tableau.Migration.Engine.Hooks.Transformers.IContentTransformer`1) | [Code Samples/Transformers](~/samples/transformers/intro.md) | +| [Filters](xref:Tableau.Migration.Engine.Hooks.Filters) | [`ContentFilterBase`](xref:Tableau.Migration.Engine.Hooks.Filters.ContentFilterBase`1) | [`IContentFilter`](xref:Tableau.Migration.Engine.Hooks.Filters.IContentFilter`1) | [Code Samples/Filters](~/samples/filters/index.md) | +| [Mappings](xref:Tableau.Migration.Engine.Hooks.Mappings) | [`ContentMappingBase`](xref:Tableau.Migration.Engine.Hooks.Mappings.ContentMappingBase`1) | [`IContentMapping`](xref:Tableau.Migration.Engine.Hooks.Mappings.IContentMapping`1) | [Code Samples/Mappings](~/samples/mappings/index.md) | +| [Transformers](xref:Tableau.Migration.Engine.Hooks.Transformers) | [`ContentTransformerBase`](xref:Tableau.Migration.Engine.Hooks.Transformers.ContentTransformerBase`1) | [`IContentTransformer`](xref:Tableau.Migration.Engine.Hooks.Transformers.IContentTransformer`1) | [Code Samples/Transformers](~/samples/transformers/index.md) | #### Post-Migration | Type | Base Class | Interface | Code Samples | |----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------| -| [Post-Publish](xref:Tableau.Migration.Engine.Hooks.PostPublish) | [`ContentItemPostPublishHookBase`](xref:Tableau.Migration.Engine.Hooks.PostPublish.ContentItemPostPublishHookBase`1) | [`IContentItemPostPublishHook`](xref:Tableau.Migration.Engine.Hooks.PostPublish.IContentItemPostPublishHook`2) | [Code Samples/Post-Publish Hooks](~/samples/post-publish/intro.md) | -| [Bulk Post-Publish](xref:Tableau.Migration.Engine.Hooks.PostPublish) | [`BulkPostPublishHookBase`](xref:Tableau.Migration.Engine.Hooks.PostPublish.BulkPostPublishHookBase`1) | [`IBulkPostPublishHook`](xref:Tableau.Migration.Engine.Hooks.PostPublish.IBulkPostPublishHook`1) | [Code Samples/Bulk Post-Publish](~/samples/bulk-post-publish/intro.md) | -| [Batch Migration Completed](xref:Tableau.Migration.Engine.Hooks) | None | [`IContentBatchMigrationCompletedHook`](xref:Tableau.Migration.Engine.Hooks.IContentBatchMigrationCompletedHook`1) | [Code Samples/Batch Completed](~/samples/batch-migration-completed/intro.md) | -| [Migration Action Completed](xref:Tableau.Migration.Engine.Hooks) | None | [`IMigrationActionCompletedHook`](xref:Tableau.Migration.Engine.Hooks.IMigrationActionCompletedHook) | [Code Samples/Action Completed](~/samples/migration-action-completed/intro.md) | +| [Post-Publish](xref:Tableau.Migration.Engine.Hooks.PostPublish) | [`ContentItemPostPublishHookBase`](xref:Tableau.Migration.Engine.Hooks.PostPublish.ContentItemPostPublishHookBase`1) | [`IContentItemPostPublishHook`](xref:Tableau.Migration.Engine.Hooks.PostPublish.IContentItemPostPublishHook`2) | [Code Samples/Post-Publish Hooks](~/samples/post-publish/index.md) | +| [Bulk Post-Publish](xref:Tableau.Migration.Engine.Hooks.PostPublish) | [`BulkPostPublishHookBase`](xref:Tableau.Migration.Engine.Hooks.PostPublish.BulkPostPublishHookBase`1) | [`IBulkPostPublishHook`](xref:Tableau.Migration.Engine.Hooks.PostPublish.IBulkPostPublishHook`1) | [Code Samples/Bulk Post-Publish](~/samples/bulk-post-publish/index.md) | +| [Batch Migration Completed](xref:Tableau.Migration.Engine.Hooks) | None | [`IContentBatchMigrationCompletedHook`](xref:Tableau.Migration.Engine.Hooks.IContentBatchMigrationCompletedHook`1) | [Code Samples/Batch Completed](~/samples/batch-migration-completed/index.md) | +| [Migration Action Completed](xref:Tableau.Migration.Engine.Hooks) | None | [`IMigrationActionCompletedHook`](xref:Tableau.Migration.Engine.Hooks.IMigrationActionCompletedHook) | [Code Samples/Action Completed](~/samples/migration-action-completed/index.md) | #### Registration diff --git a/src/Documentation/articles/hooks/example_hook_use_cases.md b/src/Documentation/articles/hooks/example_hook_use_cases.md index e1c8cd70..db10ea2d 100644 --- a/src/Documentation/articles/hooks/example_hook_use_cases.md +++ b/src/Documentation/articles/hooks/example_hook_use_cases.md @@ -1,19 +1,19 @@ # Example Hook Use Cases ## Remove Unlicensed Users During Migration -First, create a [filter](~/samples/filters/intro.md) for [IUser](xref:Tableau.Migration.Content.IUser) items. +First, create a [filter](~/samples/filters/index.md) for [IUser](xref:Tableau.Migration.Content.IUser) items. The filter should check the [LicenseLevel](xref:Tableau.Migration.Content.IUser.LicenseLevel) property for the `Unlicensed` value, either as a string constant or with the [LicenseLevels.Unlicensed](xref:Tableau.Migration.Api.Rest.Models.LicenseLevels.Unlicensed) constant. This filter will prevent users matching the license level from being created on the destination site. Additional logic is needed to handle references to these users since they will not exist on the destination site, for example if an unlicensed user owns a workbook. -One method would be to create a [mapping](~/samples/mappings/intro.md) that maps unlicensed users to one or more alternate users that will exist on the destination site. +One method would be to create a [mapping](~/samples/mappings/index.md) that maps unlicensed users to one or more alternate users that will exist on the destination site. This will allow default hooks to update user references to the alternate users. The filter and mapping are then [registered as custom hooks](custom_hooks.md#registration) with the migration plan. ## Filter Out Content Under Certain Projects To increase flexibility, filters do not cascade, so filtering projects does not automatically filter content within a project. -To filter this content, create a [filter](~/samples/filters/intro.md) for data sources, workbooks, and other content types as desired. +To filter this content, create a [filter](~/samples/filters/index.md) for data sources, workbooks, and other content types as desired. The filters should check the [Location](xref:Tableau.Migration.IContentReference.Location) property to determine if the content is in a project that has been filtered. This can be done by comparing the path of the location's [Parent](xref:Tableau.Migration.ContentLocation.Parent) method result to either a known set of project paths, or by looking up the project in the the [migration manifest](xref:Tableau.Migration.IMigrationManifest) to see if the project was migrated. @@ -21,7 +21,7 @@ The filters are then [registered as a custom hook](custom_hooks.md#registration) ## Rename a Project Content items are renamed through mappings so that references to content items can also be mapped during migration. -To rename a project, create a [mapping](~/samples/mappings/intro.md) for [IProject](xref:Tableau.Migration.Content.IProject) items. +To rename a project, create a [mapping](~/samples/mappings/index.md) for [IProject](xref:Tableau.Migration.Content.IProject) items. The mapping should change the final path segment of the project's [ContentLocation](xref:Tableau.Migration.ContentLocation) as desired. Manipulating the path's last segment can be easily done through the location's [Rename](xref:Tableau.Migration.ContentLocation.Rename(System.String)) method. @@ -29,29 +29,29 @@ The mapping is then [registered as a custom hook](custom_hooks.md#registration) ## Combine Projects To combine multiple source projects to a single destination project, a single destination project must be determined. -The destination project can either be created before the migration, or a [filter](~/samples/filters/intro.md) for [IProject](xref:Tableau.Migration.Content.IProject) items can be created to filter all but one of the source projects. -In the case of using a filter, a [transformer](~/samples/transformers/intro.md) can be created to merge permissions or other properties of the combined project when it is migrated. +The destination project can either be created before the migration, or a [filter](~/samples/filters/index.md) for [IProject](xref:Tableau.Migration.Content.IProject) items can be created to filter all but one of the source projects. +In the case of using a filter, a [transformer](~/samples/transformers/index.md) can be created to merge permissions or other properties of the combined project when it is migrated. -With a single destination project determined a [mapping](~/samples/mappings/intro.md) for [IProject](xref:Tableau.Migration.Content.IProject) items should be created. +With a single destination project determined a [mapping](~/samples/mappings/index.md) for [IProject](xref:Tableau.Migration.Content.IProject) items should be created. The mapping should map the source projects to the destination combined project's location. The filters and mapping are then [registered as custom hooks](custom_hooks.md#registration) with the migration plan. ## Change a Published Data Source to Use Tableau Bridge -First, create a [transformer](~/samples/transformers/intro.md) for [IPublishableDataSource](xref:Tableau.Migration.Content.IPublishableDataSource) items. +First, create a [transformer](~/samples/transformers/index.md) for [IPublishableDataSource](xref:Tableau.Migration.Content.IPublishableDataSource) items. The transformer should determine if the data source needs to use Tableau Bridge, and set the [UseRemoteQueryAgent](xref:Tableau.Migration.Content.IDataSource.UseRemoteQueryAgent) property to `true` for those data sources. The transformer is then [registered as a custom hook](custom_hooks.md#registration) with the migration plan. ## Tagging Content During Migration -First, create a [transformer](~/samples/transformers/intro.md) for the desired content types that [support tags](xref:Tableau.Migration.Content.IWithTags). +First, create a [transformer](~/samples/transformers/index.md) for the desired content types that [support tags](xref:Tableau.Migration.Content.IWithTags). The transformer can then add a new [Tag](xref:Tableau.Migration.Content.Tag) object to the [Tags](xref:Tableau.Migration.Content.IWithTags.Tags) collection of the content item. A default post-publish hook will then ensure that the tag is added after the content item is published. The transformer is then [registered as a custom hook](custom_hooks.md#registration) with the migration plan. ## Embed Connection Credentials -To embed credentials in connections, create a [post-publish hook](~/samples/post-publish/intro.md) for the appropriate publish and result types. +To embed credentials in connections, create a [post-publish hook](~/samples/post-publish/index.md) for the appropriate publish and result types. The hook should use dependeny injection to obtain the migration's [destination endpoint](xref:Tableau.Migration.Engine.Endpoints.IDestinationEndpoint). The APIs of the destination can be accessed through the [SiteApi](xref:Tableau.Migration.Engine.Endpoints.IMigrationApiEndpoint.SiteApi) property of the endpoint after casting to the [IMigrationApiEndpoint](xref:Tableau.Migration.Engine.Endpoints.IMigrationApiEndpoint) interface. The APIs of the desired content type should then be used to [get the connection ID](xref:Tableau.Migration.Api.IConnectionsApiClient#Tableau_Migration_Api_IConnectionsApiClient_GetConnectionsAsync_System_Guid_System_Threading_CancellationToken_) of the connection in question, and [update the connection](xref:Tableau.Migration.Api.IConnectionsApiClient#Tableau_Migration_Api_IConnectionsApiClient_UpdateConnectionAsync_System_Guid_System_Guid_Tableau_Migration_Api_Models_IUpdateConnectionOptions_System_Threading_CancellationToken_) to embed the credentials. @@ -63,7 +63,7 @@ By default the migration SDK continues migration if a single content items fail This allows for partial migration, but if fundamental items such a user fails to migrate, downstream items that reference this item may fail to migrate as well. Canceling the migration after failures are seen when a batch completes allows for faster intervention, while ensuring that items of the batch have completed and are not partially migrated. -First, create a [batch completed](~/samples/batch-migration-completed/intro.md) hook for one or more content types. +First, create a [batch completed](~/samples/batch-migration-completed/index.md) hook for one or more content types. To inspect whether the batch migration has succeeded, check the [ItemResults](xref:Tableau.Migration.Engine.Migrators.Batch.IContentBatchMigrationResult`1.ItemResults) property of the context object. The [status](xref:Tableau.Migration.Engine.Manifest.MigrationManifestEntryStatus) should not be the [Error](xref:Tableau.Migration.Engine.Manifest.MigrationManifestEntryStatus.Error) enumeration value. If an error is detected, the hook should return the value of the context object's [ForNextBatch](xref:Tableau.Migration.Engine.Migrators.Batch.IContentBatchMigrationResult`1.ForNextBatch(System.Boolean)) method with a `false` value for the `performNextBatch` argument. @@ -71,8 +71,8 @@ If an error is detected, the hook should return the value of the context object' The hook is then [registered as a custom hook](custom_hooks.md#registration) with the migration plan. ## Cancel Migration After Users and Groups -To prevent content types from migrating entirely a [filter](~/samples/filters/intro.md) that filters out all items may be used, but this still lists the items on the source site. -To end the migration early, an [action completed](~/samples/migration-action-completed/intro.md) hook can be created. +To prevent content types from migrating entirely a [filter](~/samples/filters/index.md) that filters out all items may be used, but this still lists the items on the source site. +To end the migration early, an [action completed](~/samples/migration-action-completed/index.md) hook can be created. The hook can use dependency injection to obtain the migration's [manifest](xref:Tableau.Migration.IMigrationManifest), and can inspect if the expected content types are returned by the [GetPartitionTypes](xref:Tableau.Migration.Engine.Manifest.IMigrationManifestEntryCollection.GetPartitionTypes) method of the manifest's [Entries](xref:Tableau.Migration.IMigrationManifest.Entries) property. To cancel the migration, return the value of the context object's [ForNextAction](xref:Tableau.Migration.Engine.Actions.IMigrationActionResult.ForNextAction(System.Boolean)) method with a `false` value for the `performNextAction` argument. diff --git a/src/Documentation/articles/hooks/index.md b/src/Documentation/articles/hooks/index.md index ab921de5..ac999243 100644 --- a/src/Documentation/articles/hooks/index.md +++ b/src/Documentation/articles/hooks/index.md @@ -21,10 +21,13 @@ The Migration SDK has the following types of hooks, categorized broadly based on These types of hooks run on content items. - Filters: Used to exclude certain content items based on known criteria. + > [!Note] > Filters do not have a cascading effect. You will need to write similar filters or mappings for the related content items as well. + - Mappings: Used to map a source item to something different at the destination. The original does not change. - Transformers: Used to change certain properties within various content types. A good example is permissions where the source and destination have different identifiers. + > [!Important] > Transformers that change properties like names and IDs erase references to the original. If that is not intended, you should use mappings instead. @@ -44,7 +47,7 @@ These types of hooks run before or after certain migration events. This diagram displays how each [hook](#types-of-hooks) is called as part of the migration process. -![Hooks flowchart](~/images/hooks.png) +![Hooks flowchart](~/images/hooks.svg){width=70%} ## Default Hooks diff --git a/src/Documentation/articles/intro.md b/src/Documentation/articles/intro.md deleted file mode 100644 index 296686dd..00000000 --- a/src/Documentation/articles/intro.md +++ /dev/null @@ -1,5 +0,0 @@ -# Introduction - -The Migration SDK is primarily written in C# using the [.NET](https://dotnet.microsoft.com/en-us/learn/dotnet/what-is-dotnet-framework) Framework. To enable interoperability with Python, it also includes a [Python Wrapper](~/api-python/index.md). The articles in this section delve into useful information to help you design and write your migration application. - -This documentation also contains [Code Samples](~/samples/intro.md) to give you a head start. diff --git a/src/Documentation/articles/toc.yml b/src/Documentation/articles/toc.yml index 409b147c..a80c5b95 100644 --- a/src/Documentation/articles/toc.yml +++ b/src/Documentation/articles/toc.yml @@ -1,5 +1,3 @@ -- name: Introduction - href: intro.md - name: Configuration href: configuration.md - name: Plan Validation diff --git a/src/Documentation/docfx.json b/src/Documentation/docfx.json index 718976d9..da5677af 100644 --- a/src/Documentation/docfx.json +++ b/src/Documentation/docfx.json @@ -85,7 +85,7 @@ "fileMetadata": { "_disableContribution": { "articles/**/*.md": false, - "samples/**/*.md" :false + "samples/**/*.md": false } }, "template": [ @@ -98,6 +98,11 @@ "noLangKeyword": false, "keepFileLink": false, "cleanupCacheHistory": true, - "disableGitFeatures": false + "disableGitFeatures": false, + "markdownEngineProperties": { + "markdigExtensions": [ + "attributes" + ] + } } } \ No newline at end of file diff --git a/src/Documentation/images/configuration.png b/src/Documentation/images/configuration.png deleted file mode 100644 index d50feb3c57869a4cc295e7469a6381c69f3fc56e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46889 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 diff --git a/src/Documentation/images/hooks.png b/src/Documentation/images/hooks.png deleted file mode 100644 index 91729a966632dc9656b02e828cdc0eb7e2b44f28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 487916 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
|= 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
    mmgR&9%sI3hnsw*7s(l4 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
    Qc&3V*KdI$G~WIQ zj69DV$K(sQo39-}*>D0CUEJ5>Z_@Eh|01doR zVAinsjAiA?*#StJ#W*Wt8#t2AwI}K_T*^XX^ZXLAs~$&nVsZPRf!B5V=-0OUs8(p% zEG8JM7aq!e9%182Qk`Ymu%^(Pa$|AN+_@S`YI!$$9CC&%m$A+gwHvpEKh=VD`QXfP zDePl&ci=wsc=yd6NpHCKCnj+Z^=|}5-yz6>-=DRK#2O~30*UC}jx&y_@n&A;l#5F^ zPl5H7j3FO@lj2;&J5#ht+A>K{O-mW%S61~(twzs`?;b7Luoj5d5(;fx5uIQA<&Zv& zd(JyxT#F(emICOwWh*6{*u&9#KYrv3cC-<$07wG)<}O zbT06}>8G35gO3IU2GWWtHP*fFw7*X7;4+Xjy1Ygz_?uLfD(> zgW-4c*4*IJMPVSGJ4-*^;z}~S^HK#n*CYH^lIRtOQ|IBHhx8gx?81KJIJgJ%wdhyBkZVG zfyJS1z#8@JHI#sbJNV_@#LTplgnyPI%3Bo>;h~3+WHfII{7wiNHxr&Ywtl8!qVtpd zfVHB^)KkRVf}bORMuD&7E)8E@OEB7K%6QyqE1~fNIaKb6thhgvWoseY;$5;nGtN%n zF~lhCAbeH5YVVC?475F_iJS4;nuV=c zSk1sLptUO2kfmrlxt@a}cy22t{|V0P#ZBBBKe?>tHDtzq$c2VhS6R)p=uI#iYY1hW zrYtn}YzsAHY1mE{$8QRg#*;;51p)Xn%Ck zHer8sus2Zbm!?c&!X(bdm-EHmjbg9ZU$5r$>;};OFvX|{Fb(*;A|+ZNBsD| z&MZ>58BbM`Up}yDT_J>B9X`JwEK&ld+Mm)nb<-i!+2peZ- ztt7cGH{g@G96H|Ql_=(?K{ zcahBUh7a^FXHEHI!|(8PoJ%70*3{a(UbT<0R2^U!&V31_XgtnH605KPpz&fEj#TEM~p|Oug<Ots!8Q$7DKTX-yDA05D z*Q~pT9ae3%XXOuc8UC0CMd(x&-M*_*wD(VG)bG9g+)`yIPM2ah?OA?()`v$uEXppd zf`a?&8i{E)mX1Lr@m4J9>2Gt6Be&U$j1t4?PswYfJHPAoY*M#fm(}A|R?y(YOxBI=);MCDw2C9q_Z?D|U1)I&|k6 zm|ZLrECbBo=yuK7o}s>W8ikztCi=Ri4Tu45tZ4_3##4`eK9{VjS$m@Qv+TQ!JAEkf zM-5nOivoA^wR|5*%D49dt*n^W4OB5ZEcd4wJy(-v8)uH|aVr?=8p(XssCc+EvH6~6 zKSsW>r~v&az=%633dBugd`>w9*%Xxu$>xqiR95_nF>XK8lD};Va+8k?&*1j!u}X`eVkCzr9|^X( zQkV^m#Ar3#{mlRbI4slv-rMJ}6rT0?Ybf|*_#VUku9`HKCt@ckO?|p-03d&tc-y(M zax1xP=AG^27E7N}%DrXleDi4`vDmX^sxRhML=r>3G2;|4KJOiNt_d3Ha^EBNUaL>M zo-iXv|3(4IF22Nd=AlvENN|ngypKKV7cR>1B$wwsW<&h8+vmUWy|xLCw&#NW?Kw{- zKCdAy8s(kIWvT$eB)Vz?DSy-6b+3DqXT+;h)W;D%QO~pn=oA6qwP)x|)Xq{N1oCm)lA^qUxlri?fgI@qjZZtr!8_wpqT;yuX}fomowwxT zU1pB&x&01J0CUe{mwIdi{QeF0yXQ+Z(ooXJ-isdk1iwCJ+KzZdbrL~88Hm^U;AG}QwO{a)eqn1^Bp|;GOoEu_8)c6(|eQ%=q)w%bzIc*Lwss@d# z*~LpYB-n6PYTmbvx|ZvOwt-U=WQbtoQl53pc<|e(>+$O!)6l1!$ggY&WlLqh5yG*@^@M&vX{zD?rNgKSqH^^yLDE~i% zYnQGGMyw#N^nohCM`f%{)q?=G23}O%1~*GjEbo(0PtRk;$JZ=`2_bV`XDbhWk#t^} z-{3q#2(x8x2oNnU%cYUf$5v5X1||+cfeJZqSc#KjbM*U720Lq|4kbt%L)fo*!iLc@14t^@R^APU%|gF z?YK!E8Wda~9E4@x#9w^Ajb_GAng#s+b4i|!Ah4zfBweUzst08@UhsZ6A{U-pvV8gy zIb9bE^KZm=utXz15^(i{dDpm!LiqcKNHR%Y-7J690N-RnHt9hr12se$a&+D_m4zp= z&GWvONzb6U?YaA?H|zy?82%$#d)VV=(PDP&hF9me3py*_V%<7^Y1O<5lifgi*n?$=KI;1=tbES3xH7HiJ1x&p_+7iEwv%fi5f)1s zxeAY{T~ONi=l;CB3%96*;cW59uA8IZ?00}4Zn4L!?)(Ap9Dt96UJ8tlcbY~;pg@Sc zypE$kGD`w3Q2neP2Fc>OznF1$H++N)Yg2wFGzhwtO29yX*XY%`z>ND9l@dka+y0Kc z+_%k=!??fx$*oDx7@)Jh)@B<^kAGinYpi#`usk1r0tjFv=Fo!BmfSV zgDl{Hy)8Swyran=`|EL3(9`@+w;C`nQ6GYIeqRW40$1ZPK)L{-bqBB|PIFAqp%2Pe z@S+^g6yyMT0@|AvD6_Pb(xWDa<}G^7$1q41(_#3oA811H(D$sDn5(DB!GC5~b~v&r z79INUnL!D({29Qk0x1-h4QCG^v5ptq^bxa$(*tQqNl4=iblGQs?F7{TBsX0?9`mr2 z?niEa?d53t=kSw-Nv#GmlgmuM*1UgcniDb2#)a-eMw)|w>cCNx&K4FwbAa#5Bt`>- z{liN}Ao~Imt^*F24c=*AeRf7xQl}wZXsnZXT$SZ5KmsYbmn0?mBVmvt*GPdTOHWv| zX7w(VrQO^WU70!odUAY_O$bihkRIIC!2q#ABLhx##o8pW39_W)b1M`B*|1^?b~-j+ z;xx~VuClfcaR%NjLyU#PjHW=@L1XA*-s~?#WA5AL&Je3(y>3@=>C)tD?w@$v`~v?D zL0d=Tvp*;BGqmew|B#lDP1OU{QS7caB&TfR5tSBizGcvBssCyMMEed>3MWs`TQ4*nyLxegLd8WMKWe)bEQ#FXm&S6PDH&k&gih@e z4aBqmw=i3fVqnW*W_lG!z@cNrYXUujKGzPS)G8vuJ{X``UETmxPI@i_Qyg+whyTck z9>LN|b2O(IL}7!hf+e|oVRi|GIh)u(c=h3(kEAoeUg;h?Mv~*RGp+8?w2S9gA<=UP zoV5lT-7qJct4X&*B(=B9**;)YC?cNVr9+k?y`KFSxD$y$Z5*dc<#mIvmNZAdR zd43d#t`_MCR1F-QCq}*bmVC7MwO?qTMY*G0i@}nZ0Q3OkDhU7n@&?F;VM3^>%Jny) z&aPlNphfVS=?c>3+_`z6B`cu$Q?nNXLdD^9AR!Xk7m|;Uuv@PH(^s_-n;bsEH$(M| z_Bk*?qvI>S98~c0eR1(B*LCLI;3n)FXmz#Bk?}%1qQOR+eDPA(w{>h%Y$^)~}QOXOJlb)?<;A zdM@%1A2Rs=Bk207y$OB}|20*4_;e5#PyoV03cEnTbagOlajybRq(kz_i;l+#mG$*V z5#xqZXuC=qy7TGDt~uA%UUUDoq{%lPCnR(%GuTTM{eiM@#(kb^RdoPe&`3N8bOPO{ zf&K&`mx2ZoNbE;N0GWQ%c`%sf*nB(wsOsnZ9y-WIBzJ)UXm`}_nRw*i5jRw1<)M}p z!w5H5lcgZKqZq1OK_cvS$^{bW%`~fDVSqB?gCU{Xb}h)j9W*lN{r&-&+xBnM5?ll{ zkhT9ve!gRlHZwJi8YA~NF9N|=kj4h&X9R|Rlvh&2<%{9FbuFR>lOf#p;~!#|fC_l0 zI^)~@)^1oIKCObK{&@8#?Or4!5$t)#7FfQB{g(`@uWT0kj;C*6csiXt0cvTFhwZPD zUyez+##_e9&W#gq8#ki;u*9? zT(tnB5C2z1g_vAoSN7;ZEIJnyK~io;b$NjIw*>mS2`^Af`2IT%XybGPW`gq_1qP4~()-7Zmk|MTH)pv?2)7jN$KPjPVnjgn)L$ zY`Ko=0n0=HFmb)btPB*gIOmW7`(uz(Sqsze;6EE0@EqR)3wECx=TpaYJcA50NYW>v@O=}t=s1b^EWsZ3S|K*Aqu8Ry zYrKhA6MAIebuOgYjT>2y_{mjz-k#8T9HV%L+oyzW|CRupoHTG(8k+zkso}7l4@1|F zG-@^McutMjG=vKo4xOtM47BhAapd9Ywp6^nhAn@D7Tf|{O&S=1&wf0MlSe|Q6{QWV zIp8>j6idLjwF?a3Q!d*1*F+S-3I_XruIX>I(RQ0Tnl>V!vU#|)^s{pi-@W2rkuYFc z_yA^H#qK{MCQElJLU8)XuqjSK!m#4`GlWS{EV}KkR?gjPK}L|H$#W<$4R+F2+_K+i z9=_oZ+~OpWS2OvWmpK2(lp3r9D~l~f13mwGPDwHiO_>iB@!IwE=Z1U9t~>!=Ug+(u#pwg@Ad8h2PBp9L z6n$ahmT0L0@Jg(*Uk8{V!9Yb*+7s9HwpmNFMUOMiYNfYeaKPzaXdg3>SNPJ?Oa9^4 zDDgyhTlZsX?*pp|5-f^v@1vmihe&$R;SG9)7?}G5%bF`FM8YSrg}NT$CxsfxTf{H4 zQV4w4^|X~+umh|LVAKC7V$gMf)J}~>x~+UfnYvAzA`gUxfSB~vX=b`5N9)N5qg$X3 zL3;Z%40L}R7+)gzd%t)iN^ZmJd`Z!$mQ3F90)5EG^^aaAeb7u=wzE_xfs%)KFqMYX zyK#1*<v$9Os3%INa&T3s7Hd5_r^oMSIdg{&79Iqb@p)@#C+GgAx6f* zn8jeApQv%=pXWNA?!{5@=t%HKK_CXb&gB-3x@M%}A1CWm(!9Zebos}tuRH=Qs zE~qKGIIfjLQqh0^$;U#PRxBftSvzo!CP8alCAElE33$)G>(wnlW%CnFIna5Y5ifq1 z6N0dRgdh+s6WUfo@WH=MP#!^94M1Njueu@za;XHNM~uV+WM)I|LeO^OpUCX?{bXaS zdJqfQTLWff=xvlixWLNkR%T(?YUcws=vjGr{#Ad6&SfOR?Mt$klWaj#3F=PZq$n>> z@=K>n&-e=Uq9I8yzA7R0EdGrGn<+kg(*n1j`Y~@_Xcj@X z)5fnNsd--rDLnSkFDp;*!QqpiBGWIERiHtGc++J6XJ)HlCk;Y`r!YT4 z>zbCm*n+vWf#|rCzT^Cckjz^w+_D|;`*3H_vO-}6$IDP3QbnZW9-Ir-0FD!TED59X z$J*y}VoZ|F-HJx(Z;$-y<}{CE1dxF(GMt-%>%VkDhxB4WAkdn}zJ|=Qcs2mEBY!eJ zpX%D#NPs`ws#T9GB%tV5;6Al7URooN|z? zZZH7Y@6{At^MWST2(%KJxuz`SdC^lR50sEap9GE;K@EUQ>Bp%wx)ssOc>E$v!F z9A#R?dQX@Da0h_!DxigcuEq_kZ9Imp8fwCvd$Np-I%P#pY*TkJF<*29E*uTFo1Ng|K==*Y^4exZ2a#sZz^ zTDoomeCB%ztO#^Nvt+4ki7vzkdw9BsN*B7eoh~P+yN<7=K=!WAfMhJ6vS=jpVGb7= z|BrXi?6KlcKcpis$^?X9c@VnX2)}`nII+GFB7anesz3VNs~I^{@9B`QK(s34>NsKi z5axky2S?JixgYl|rA7^Ou-bAZ{ifxKTw#rtxp-Sb*XFc0cf|en(#4fe%@vDK6N(<; zvq)jC>4HNsIyFz!gY7F!ryB2IVTscLw7~o=?A(+~^l!7|z95N|p1<*`M+){UnJdlA z1KDI+x#^9!UcwWrWaO0S_yvp?8?Sqdi#GFND}Eh}xz_8_{myl% zcNLsnaS59sO>^7Pn%8%56q-I%qocTBJGVa)UA8T%)va}nCY22>6P!i)R15uE$ompq z=+hPTxjmP9vEz-|6ivGlp5?1ol(@ zY1kK|r>i~d6z5kP(~eH+OL3RGu6+c(!PL)7UouXXGIoh>p-$dXG{41!UQd1F&MoT9 zzoHp4%{ddyO1oI>qx7E%<4N3q_m@u|diIfl+2@b~J+m+K>CCF;nZ}KR!Ke$w<5b3( zuh>sLir%mPbsSsW9?atWrt55~oUnt$l;d0odhQH917@7*_MP7+#3DXwbUC}f?jUUgi_Zm{Ag!otS z$EJkfOcR`ptJGE;^|!}(5T1-X752xybQE{*dpCr+q!@ZmLPL@*Ua4drUu0UfR*@93 z9Y~{Zk;L<*boFtW+g`ooIeAW&+y}?iD>^?^3v& z?nrjYuOT|r%6i=TzM3Trf1kmFiAQ)HEDDHGSn2GEInx)ioO}9n-*+` z)Z=rgrJJ5{J=);CTaPu{yxJ34Zt1>pZ=E8rXj6sQby|i&XQQL6gq^}d>M9r9v5w9= zhi3#uZjWjjP6A^Sus@xssaMQY;?C^)wRmXR)f+qZjMnCytaTpf*3Uc+Rj}-U|0sze zIIAG(8FgKMUosk^Ag8i?F{qW^e$M@h!c*+14qta#Q**nr#=CLG-Px1EBKWzT0Z6sy zRbHOa+|FM;vZ>z78{;-9NS~dpcjr7jyeta37{`5m(y{tlYi3rw``-4-msz5-F`E0f zJ)`+m{q34F4D;qCEKVT@?014nC|+!&OwV`_9iIGl6Azv(L+|8UY{Wb+CD0BiPvPf+sEZ==AQ+l`ry1c?YyD zxaQ^M(|(QWn>$PIImU;gyqz*OE@hnXK=b+X8xncR}QIPG6ef-0{ z@i76DqRfrXbj4>^m*nkn=4-=0ugvV0+Iluf%kDdbZgeSdpVu#bHk6H84|q+Nqm=aH zc(n)pgpa~$x%oVixO~>PzJ8{J?P$-1mXbXs#9D8;Y|v;q?b7V_ogTvQUpB*8M^_m# z43Eer#$t=h44s#(*}`$aEx4^Twyn5YJSxRAvazOeKx(gf?&!;ofmW&g=G{+eLg+3< zs<09$>$-N@-M;ti^J->peB-&W?$(gB*Uuulv%h$}XQ z2J;?|Vtq&=P12pQ2VX7szZ&D`(V5Whq`1L#HRHV)t-BYmLka?toPRkFa%U%lVGX|Haj0*Y z>61p4>bpC(&VPbmGMeNt=%r~1J{??QmSRU%PmdmR$5&H$NgxKaguTBS8WBNiF1>Dx z>(l((W%UMI$w%V>_N`lk?%h+}{YI>g4*NCY&h`F#7i4se)uTP`C&ZiGXSJ@)L_aTy zu|f+1JnD(uX_jkB1V~Y64CyxdLfki&)yXbgjt(!APx4krt$>!#!;^yPcLX%qZfWj+ z%)RISZK~Vw1)ZVEh-=p9QPsyEIY&~d=Rd1w8NAb1C#4)&j)kXER>ZsA7FV3d_)iD= zofG3w^j8iy9kr1KNOdonH)vjOO<}Kh<7_|G z7+W{g?V0s;;}pAxBS5;~QvCHiG0wpoCRxg19`pOtmE!8OzfNC!^2U(HP?jxnjg`ku zkl6-<3Hf}jX^pb&-InP;oV4K z8UN?z9uF+TFAU3p#J!BumgiV03-q*EU@@!NdA%{tW=*(*7PI7$j*ABgxkBj0wLQ+Lc~ zq*{!zttfV&;U|HAD|qzc9L<;fzUK>78@|RLjHrlL> z*t%bRyvy5OI)k5k`1y^gIj#4-bH3RH2`**p`dLQps{We`)GoAzqdR5muT;Kl1cf#F z(hA;j3Q_%R55;@VJ(XU1=tSdyle!o>+nAyw(J`m?_<38=l8Ov1 zPa`#bxp%L1*%BWs=g!Tx9jGme~ls~YT zH}<~gy)AOPZQ1+J@VBj#wf)+ltz+A%tpuCG^|rl}JH+u9Hw9Ztmjzwhj`VZB9484L zc`_F5b#S(KnH$fR%3*sYgDH2H%%gX$X7|zt$$TTav1<$DfyFNDY6?;?zs#G~UBMd< zVT*Ox_yO7Sa|mMw^~LB@wO3NJ$ra6OeM|L6T*CV>qPlZcF~bs>8b?k+ z`Pr~x5q(JPcqMVIafd42CE2<&sP38WpB?ALj*or>4-x44HD%K;{t!^LkfU z&Ws$MFcTsNe}&)3TR!r5`7|)}w)N0J8-CQ-{>=>3Dl7qz`31`zbcJ+!4l%m=67z2Q_1bx_1hO z0vhxQ1DX-^c;GQE)c9&_)99_~&hXH%PTR!jm#rX-o5HJhiFvClBr#NpIu+*Yc<8=} z&=$C#NolT=C)~EvQz-YB0J_iU2eT>hoawOo(C&1ssGxyd(7mj9V18hJq~_H&9)E(2 zD__{h=Iy#HvS!!BnNq?07BXX+_clKuK={_m&WDkmCy+P7z;|~pv$N$ zIX~Te^ROj!=a;;)&>PX_yhyH!z89Ng zqxuQ^oKmvYbPQO9|6Bp%T1p#I19qbHop3hrYB0>T6LDq1d~up1bRfuZMN`7@J3RC8 zb-Vn?Ld!rbC8v$oi`PzNlJTLRFmaYbiZP~^)AjK>oaRWKF`>9Y>i^sr#?Z}n3ERFb z1YcmucCE-fWrf$u@95Mu!DNy*wnF4Yzg=9gX}*s#m{QzjbgMKw z*Gb|+qoSx0=NS@}?`MkB(FMMJdXf1W(Xw@zYfjOsvazh1l(d*PQk!H_nXWF{1N9E< zZ%!|HRtL#}&4)Id$UnlQpl>k0=~hFZ4@uFT^j1|7ggCq5m#L+{Fy!J}bZEq^zj+XEF@!7c-o4XIC zcy~}mr;Tu{E_V`bcYjS99-`@DclvL}>vzDp!pV`Wz1u=A-yDg_<}xQK#G%oHWnOR# zMfMzJ*))1&jU}2oBNdorb0!qP4_%oaT$H=$GIj<0%Wk#U{lkOq1D_B7HMp`Cn%7X$ zUBsPD0M^2d))!$S#7W7~mO?uHFM!2wsP@)Ux3vzYk|ZzgMEL4b?Pm@0$~~NO+yrN% z!kT`T>+)$tA$PLW>cL?iP#409#z&ZkIN4?Pii1+}m-}335XNV=+``90ef3Q|9=g=; zos$4{0=Ki(v(>LN6yIkQ8@4*Xw92C$J9_SrX|R63Z7f6{@H#OT=`!##_M}!jf%i*> z4M#V$de1IO!IM%!k74)KwFhS@<~co$Pie_lPf~7WqiQSU$iCf$T1nIvmC)DsF*QTv z10&`1a=YT!uth>BdORLok?WKwB0X|l2#n-Qd1O|(ITACU4RkF3Ui6*4VtrZ8 zYnzgoMmW{^Kj3vruMvYfA4kig1mQOck>zq36I~BOFechDExx(~ryE{w&V8$xjYK%?4oIy=4+g%>o%T1Re zRx4R2OohJvyo5q&rt$hlK6Ujs*U$QynH3?i{?8BEdgp_tGBz@b5H)MvKKS@W}6S30Zlj5?MhBTSCkCYf?VlpeVP#meO zPtz_l#f1_uFm}Rmw-P_420<5y(p{$46L*?5QRlvt;JypUD00Kd{*?W^M9MojJ{byXJG7IXVTmW}s);R&th7UY$UwF{Iee*Q)TI z)>|vIy}?UUmbNdR$hn%BkHL(;6jJPWiX(bZ~Ff88qSvpOBsN3fwc-63f~3`0y+1EKx614L#@kGiE1A&yCt~N z*uzZ|eXqpkM9up@=G699tVw&A0qjIj;OP&ieg0o-YSvpcr}&P+{QtlM2d zi=}wTC_UPWa9!~+OjEY_d0Rp?zu@vNk38)l=6ZiX!#Ft&X!Y&#iuPpAD2m;s^F=kz zK!6uRe>5z%et**Q%u>&aSK;EDes0}W9qm;$&aeIx;B88(y&{{#&o2(brwZYgb43`d zpbFF3cA*n1e5HNzt7v+4x@(J;aiS|Az;h|7oPbwkwt%fUYN(dYltSr zPmz=6Dgg+vJaU2G2U}nK&(6j~UB~ek}kR*SID6&26<1b9S zE!Cw9Z@HFzP*b2gkvg&JMCq%-yUzyrwCuoW2875|!&NP3V@0xRi5p?i9tx*Soco~_ zV~YLMYrgzO@PS$US!66wPEDwgBV8L{DTB0*-g+B=B@y{U%$)+6sNd{yiy!mY6RB6) zV*I8%lVcFS(jBi?wlm)3HG@|{v0RU$k>81z2GU^U&JV+>%NCaINOA>PZW^4U2fYTP z`_O*vW8;&@qw=sunhOu54e+W?05zNb3EOfj{f zOhy7h&&UW&2aowYkL~!T!86;wH-ZS`7nBaewmN(Rx$!sq2j&;p@o~+7|NK79$;lmg z)CxHzt>k?q`fCTH<^^}gwXRfpn8%vUuMD+E9)VE$Z8Lb5ATf6YL;G||XITNBouf&5 z3%6p%L$u2`#?&7N3K~|n)mTPr)Uj%Qv@!JT_3yq9qsO#}eZWn>Ef2OTTj=4%UaWK*Gv|7?obFFWr zydG?JKb4JOx2v-o!O?h4fh#czWLb6!y+nzj5AQcOz9rNWVU@cx(jl7bAen}h7Vl5D zM3P9FB9=2h;sYd*lLjB=_oA?2^|OKd!6zRv(Ui6nr$K*&+fArH9)G;_bxsy<9{YGb z3TxO@qllkW00R_9?TT$%a9tKQhg%6%@>+G1KF1C7-#yr532(b-PxzHcbjLR|Hi4FIDAS{Xh$&beX<{!GQT>5W*^@m{9ZbDx0bd>`b!%s&A~Pr`|RyM69Cu7`*}VR z(M5?_rHGAAoRokyUAqL(2;@$4`->LTBV zF|k<2YP9f2tu>fR2jWOEM+JlNATQ$zK3tH~EaWZ@MS2?PW= z8Nvln{+mua1gJUPf${4+V1)h}k0-2_-Y4lF@E0FIj?3to zuG3NT&vDYgq+KbF(lnxZ14Z9K&ZF376{D}UkQj;& zYb6WjxKm*pD<5y^u?K6a;jPOsk1i^>oSPxcR@`YO1e&K;mDzX)y0da?-1QdB&xCw; z_WQhbFdOnA)LWvmUu8~(p38IZ?5lH3^04~n{a$3$(&wCdZhSV#Sy4BTOeoSdLG#BP z0JBV~d%`oK*r+l+u*bqCcOt08DqxulI{evcjJTn})wp+4&^)OCSPPKM(mW7eeyfJh(J=Y!j0J+IlD62RJj z9n}JRUP<-uOk8VP4M^ z?Os26%UQ%*l!MtW!fPto7_Ou7NGnr|P#-cwhZ%x%91|v~W>;3|w^?{o)#pjqQ-go)}_iN+)9{v1+N5tT(@^(edYPNmV(w z9nFP8d{_jJvyVh`wV=!3IdmO9tmR47P?3FVVqyRIQ^SvXy3_p%*+?ikG5V_OEY7Hj|Ek1FhACmGB~ z_pYYniAT({2??f+ZM{Or8(o5l{#xVL$*|gMj7(Sf7Bc}qN7>(pjqIfm{A6vOt#n9? zNeGRBFRlcm2UmqNtZwsZ#E0Uyd~{l2;dt+LJ9=J7Jz;?dq+bF4Z#KSNo-%8XibuFz zfdzzcBRpM(2KIH1clr*Bog1hkdzis8LPV1)N&n$9@4e68pbPvMUbCR-ChaMiwljxf zE^s3{D%c-SZ;MjX>Xz5(`uf&QfK5h8enX^+*VgqH#~{9+iR-I3X<<5i@pY+ml_r^< z(aF)bRBk6nW#*wLzvfIr`oAqCGXpdtwv#zb7=#X)UqMg; zI6O2qTmActBf##^N%3kLk6!0? zpz9pUjND5g(J*wVUz__8a8FGoT<)#)?`*P5a-PLV+?DU^yM0a#$i zZ7LHpm7CzCl(UL*Gxo3XUh0gC#;Ix+Fq?j}5*%(N0jmWZ4AfbQ2pGk)Wipp<95*n# z2Mr15QLWyC=ooqG-!|x5Sc9x=Pla`25T$Ts)nyJfj^`@y#tib1TJF9wdvx9}%t=U} zg^lIb?+NW}hMavWSoou6pVTKLQ*8S>vr)4SVKM77ZugT^EFe^4@o4oTWGfaEbIZwz zf^1>pELLlmth(>uf_9J^{G^YeMmaQ%J+F62!9wxhWfK5LEa;wQ|EMEjUfGKe<-Tu5 z{tm?Neg<7hhFm{w88(TFVScmMCU?tbt+Cow`&6b=Cs6

    IV@oc$P(3L>ESvgJdOa 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

    h7)EXVFrLv`+ItLk26sipp)hk9vNw`LmJ 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

    M_My3$h1H>Ywf-$mr{^sG8J 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

    Ipcb%McW|FP5qH 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

    sjaUJ5>0G{4-b z7#tX7D5TLG2Pdb0E0GxrpTIOg3uWKvuCu}Rd@;S&Y|nl_bT0ty-nn5hghV`*7A6&wA3 zG9g`0bE>MkKK`aRg84OQzP_RNDH_ElbSE6xgGSYKPXJcze~9!g{_(#7)-;UA2=g3_2{l9URsd zl5hUK+x$20p7^G?%@;AU3tq26&tzd5h4oVb)^3WpBiCynPB1e3BO55G(t!xQV7ydI z+it@yw@LaRXnF!5+)!yPapVs|QX{qMiM9evfr%pl3Pnq`quSHPu55TGe?C2Jm zluZ?fj`vI2sZGGjM4oyxDOUrEeJFGC(QmircaQ3f;fV!^Qw!|!W%jJu>AMp=Wt+VX zxQGFi67`>*Ttm++ic2*-o^4F zon_)-_eaiRz!}58W&|jW0l(T_6UE*VtC$9o{qUqNU79oh9V#Qye*w8GTu~#Xsk+Lr zS?wpy{Y9<3FvSumvy)XCeF(cMhqT!|5s#o&0EzS$rFmgVVC^GrGXNWKs=N9#HkkSG z1Lw%5?$#IZb<>-&6amyFWII>b*t-2RLnY}~Gk3~|EkWr&+-mv7lK zKhSSbYfF`Wbq2;~hGq8+!&d`wKz0Crot#&c$TlVU0Qd^zr=C1|20a&Bwid6THhlZc zM-+YSry?;xvO(fqd)N6%!crQB^h|Q-oucb1zCEx3-y6*!VmS4V7J@f>z)}pbHNdJs zFy>c(tzPb?#gG9q>E4(3sg;2PvkK<;8jyQU;CX~ZOCJQv1|%gPaB`a-=9+faJo<;h zOnG3^uo)zDXwPifWr#lzAGV8~RM!oQhgdf>x0{m zYxyf!l*KquDv|O;Z{zJsNn&I0K8cq-n2_RWR~WSZj)C40Fr*nlz(eO+DyiI)w`WJ+ z1&*YS8a@QH$c(0%8#>YW+AB)DsNZ!;`Qf@9+ertU0o(^_%-;C3gk;c`BKB-{D~5Aw zTbLw2eFbn1avj1l2E;2+h7R04MD|xE%;sYZOT? zu0NNI{|y0!kmc7k`Au|gTGwPx(A`l zs(&0sjc<#;8e42b>bk;pv{*p4ZJOFp{4FZiesT+-veN=JC6#~4MTDK^y~^hi_z$m$Du()g>aobKIp9uIP4l{w@QDmmDkVKs^c5Pk|{$drpuku)0Fe6Z6QGJ8BwCu5G#AR#(9$&+=n^}RUMSwZKi}lodF*zQ^ zjr-;vI+ILB@{W`xYmzsglFRIX zW(-$>f)DZg6O7ExpDJtk8wxKaGzRAslU-`HDHqE1c#p0LPlAH36JD^82rFN4;r>r- z(tf$qsVRCntvcMQ|IM9trGX)U9$l-peM5s@b>&()-9+>GBvIp-$Qk>#URNNo6#>!1 z__3H7gYCEMSPI=A z9?qu=uuIFx%Jl;DNO2~W6=I3Vjo(+WYNJEfvy?$C49&NpT?M;T2&@E8wZ4g9!Vf+K zd{%BDhp=n}U)|!n^*mSc>=_mF>d#tTR}d3Q?*t6FhT&*+0EZ?cu7D>{p|d>Qq#; zUz_j^jv5adj$!c;>Da>v9WT*_&KF5!{8qtD6TMr4iNqAjuaouGYj7xB{a45rohw`_ zby$qJ_#;fkKd53fbL83{adjKlUzSri39roaL~EE*R^$|o(uW=^A(?^%L9EO*Rrj_t zUDBX7Oleh4wo}oi=3Yl4%D?DtJ~oUZe6{w^!lX=v{;g``ly1+S8=&{vH#g0oQ8BPW zTfRv+F#e1E1?l@Ada|;jZLagT38$b)FJklBm;nF}ui>?eQ^UNFu~}y87xQ*l>j+c! zXr#j>%n`wnNgLKCeIXi8le-cAfh`YzQ7%dJT(bofA_25;D$`y2p7R~qBpOxCWM$@| zLuU3&Dd-k77Qx5C%`3w~Bga)#0yVGXM6k*nAgRj$PUTU-7{hp;V>Rb~IUEQ_1gQ^- zbzAq~Wixp0{9`P4Cu&N*O6#oV%@*dm~F77%;2=pQ-G4L?{d~FOND*rIp*}LB-5sd9(Y+Jd4)zFVX#2x`+BOQlFJ**3_ z%HOXEu@Py7i*FF|ibQ(>+>n`NX%0<8)Bf|ajUvl~Z2_YxO)yf@9ndC)1yX`YSbjIc`ImKDsns8T+N$<@-T7cn zsKHzWB*pb1otJrc(On;#+3d%z&di0lfH|ioRD}S5sr$Ei<(&3--ud z;LC_&JZ^ia5poa|wgslhXPFlnly9H1GaOAT=Me}#vmJ3K;;HOh_n-4Y2Rt6Rq%1aE zCWCa_B&m7YYS!S!t;Yho=HCebomd3~5Fgew5mH}`>AB?#F}_BJ#lFEsi=d{S;bsi< zy~wIq`Q`uK#%{|L9?-?0k)}6kva~(VBS(;q7up_A!5PrR*RjRaVkoq{!{y`bwtQ+6iWI-~CtuK)Cgi9W5j zjiId$x)s1_on80&c$gKX<$aLSw%=`Ql<}8}D?a=O6;=|vs`xzFfq!>mlD6NKI_)IM zTg4&GvnU~cxaOVQ2&mX&lvyAsMr_R`Zhz=n0~iB#3dG`usrDaw)*x?$r1DFSK#xwT zEOhZ;p|`9EvXON7PW-_GIcoC1Nh-fxtFV&03-$vppl6-RU_r+cS~zN_AAfo`o-Bz6PFi4Ibwi8P}pUY=p9 za5TXT`AhKl`TT$Ne?gj5kXdY-F3yvRy56O-a+e}gkd7j=G}0UfX=T(haklY+{`|NJx8^+)Alz!sigvRtEPQy9UiGg;Ku^{oN|}u9{O$=P3I|!bc}@o_ z{o?wLG&AMCUZmC5FKBH~fjqi@ZL)+e<-A8=E0=K7UU$P!0KdI|TG4*7WJmL?yr=>Q z)fv<|wzBC+xNmMh7R1Ho*vb>mv3ht1xxWQQEnM6md*=Z|FN90oW$2QSoD2^bSAw(x zMEY0#q0I}CmrG&yv#;wfWm*wh-dnplAZwu_=yHU#3~Pj}xxRsg4$U<+JoD~e`=I)n z(+vsjrLR~SV*419^Ou;q4zD&C3p-oImRLW5RnvgNVjvgVtsS<|yjgyx9uv2ZsnxB9m%qd2*T5q|QZ7KL{B_{M`>lHh9T0%=#b)BV{OsDl1LgsJ z8?k{g#x9@D>MKpAm}%v&V9mmq|MtS5^%#Ckxq^&Eo(r;fU?0Ms|DonraNio@6Qo1# zk1@Uguf_hB{=hT!VhZkcoj&mW9YU0J6?v!i4bx3`f)JQrk)&FJ1U8HvsvS8C7_)Y9u@WcjL{m4QM zG=#8n23K=O>DMkf;Neh!EdM0{tEcc}rtmAv&Ks``kh@mSjLqg+9XTiL(OHCe=XEat zJ3K7u#TmOBq&ZQ<8H;q1f=Z!=&LYkA_<~~=k??o%8F`syh`ny<-~&w$eACj*0l-Ua z-|!!E>X&qfcO$Ed|C>Mqx`_?{-P~|y$j$cAW;|l{?FAZ|Lf*$g#t`7wxdUJhy!iY7 zKBZ3Li_fiuy;hkZ_A6=E+8I!-ou9gwk$jMy@~QB=-rU@k$;Jn9`>8n|vWs`&sjUNf zK<1HFL0RM0SRyA52x-i9_O z#7l3wF{VfjBKFevp)n?6cb^lM-(8_ZBLMlO6S>fH25GK{cv?;5SteFvqPr!@(7)x_ z*lQ?T?EUG8bjFHDI%DnLc=s!1Bs7m}qEJ6~m1V>x8uBWk>_J1Y{YC!D9{is~1^%Zb z`-dhrr^q{qIE=(|T6tS(*Y3XmV66b@!UlHt|BDy^Po>6=9TV?X2EOju!Om`vKnRV) z-T{-ga?5h2X44Z{tdLMx7N&@hhcn^CNpn}%FH3tw8%XN6*T-7UBAMiuNfc!(Be(XZ zUjQR{!nk?0oRtaE^a?~UtHiJ^(eOsii6SkbdNVt->wh&q`YBxXx?rzyM0!se(0un9 zK+grE+-ytRPmnQW;bRgsVdto!M23eXNsU7V(soI(W|4Ej;91_xo6la%y|UV(yGNp) zUT^n;RkNTZAUmKX8nGeP3z?-)sbxF5O5EyG!O{A=Y1Ozu)6YBKuKgDrhcx}GKi0)r zIYqG+$XIxuRNRqnERzcykN&8%uyr;;K*i_}lACR_IAmt7fi~_f63iwYy92Z+bh#@u z6Yf+l{xReY;E26s{a){v)$fy;fS`{MOIAYi9>kG`2fz*?%%udcb<{PFnUwk0d3Ccj z;t~kqRIy||J6`;vyeMcogWwaO70$n9)W>;u zlSJ^4TPjh?Xw%p)qXX<4kw$H|-?3-tA#3V<{!hY7#A=YRMTD=g4WvSnlaWe9{CvoN z^|iH@gejnZ&Nf4iMg-E~7se*V-q{wSi6k{2L9GToBSiKLb%Wmp)zN*6J=n6g*(hVq z-e@a#MM&upBg8jot^9Xu%T5HNIn%ec4d{P<|7oY0>D%i2>6TG;s8mi3ckewiaOb?z%@{{a@iC#Yqu+h!s z>)0WLNkkP8(}355M(JFCd?uCidBGPQjY!!^C{K^LEmjANo#he*mJ7V3*5So1iFP&j zbyLwQf*^7#e9%GC9Sy&1(ndbD zx_!lA1L@56ypPFc`%5(DZL>D-6i%;|{9Rw&+vaP5Q;jBC#&;GLO(xOIcGa^7rUcfu z{AH;Hq!cDw4Gz#bh^!3dyL}tujA%}td@&v+!Y9RR$KP(#hZ_)Rw{Z|M43RHK-wceO zLNRqx!<+Y8ymi$9MxaLl{+A)R$T)^<=Vs2s)r$ETC-l$q@x^J6L6Q2p&!ma@H215< zx2LL=>6Hn$(%dz2&aR8mJ--~weuwPG6nJKwH$buaD7ctU-7pE1;9>aM_dUoeu2_ zb3FP_c<1BVaTczsX}8EO4(`rWKAv(?nd#fgzqo8>(U z4xxt5{YMfzcc?bYEhaj*$)6bH?nvb%{fX&Y40+6cgnHI$;rO-ld6pth!WP-QYq8>( z0!u&px$JiZnKPXkJ0YW^UW0kjaz+1vvW}_SzHnsNDrL4{aJnKp*n6-5HMN{tJd#Zra}i) zThdj9)YF+wo29p9>NhaeTAQh>f2p{$`L zN;J{$dU}k42OLN#=owSj74+SUSPTE^D9$T!Jt>ni&+B$(vwY25;x$2V)orlxfG^j5 zhoZ!$v#uCUUF)SU%5XZ97Q zhM$$smu#V}p|xQQ+^sDdL!WyWh9$F@MA}Kp}RUcM!=g33$*l~2+A($WP_*RnM6BRzHh+ZUMUx7$@hEn~ z$rBsm+Q|v+Q!;DslIu|ywI<&VVLG&o#alc)`ohbnWZ-L@4pp_bv3MEo5Ki>N)CPdM zqC~Rk9odHjsm!R{vP?z9wW%}Ge#T0ASEcqY716%CU^HHC0Va)GZ9UY_az#Jp5S!NRQ44> zH#3j-Y)3e|asm@2Fp%6n@akP#=*3Vjx%}c}qglKG?gr|UaB;;`d^g4{>z??FOjLe- zs_eT1q$Q;?bDDSGj-&D#LwN;Fh6Z$!%gx(Sd2@G-jeodt(2zd8B8#<_`>T=N%IlQG zP+!;g01QRx{2!`DcO|R)beOGPP%oi-zg1*7&?!ktS+@6u_(YfV9!Ck{9}QyAHRT7% zrAKMec;H0Q>cM00d9lgUD9wEKp5tF~SH z5XwnId~vat8(%U!LQr0KYv}*LgG~0JYFP8a>Nls5=dS3RWfj6XjJ{W_OIJ+36diGL zCzF`uR5kiiMAc!Jh*JGg)LG0nK2%#!PVMUMLREs(k1Z0`zU(8sAf!pa=14iBKlS=t zQ+=RyM9X=*ZcpIBbb1y14+cEm(Affl(wp?AgkHrEdb5F2rT3!r8fl>f zh=>yDodBVT5kimjmcTm!^>W|;-dbSx;mA zt+(GRp-f>|CeP7zgyH2-QEh#MY3uCL7wq_P*iczdbHbVGxi8V;m)oMmr;mr#4=(CW zR@$U6^10ApvM#SZkyS_}df{<=jkg?X7%%g<2$X-LWvRA9&OH3(@iF?)v?6JzAGx%i zox8PzBg`^1UVZoKV5Kmyvq!?2)imU#WAS&xK1JzswMK6(zZt#LWvO+#0YqUv!sX7IU(nA95Ro z&WpS7Yz*-p6{gpstM#$7ZCSWz@tGl%0b!_NSULzH+K864a8q7jwzG&9CZ;=vG-Pro z+hO`1_dB<;^Y)rYrg1i~$_9FUoR#siWSQ-BwzK2*BMoEXu-LTwMF5u^=P%;sZhEMq z`M|6UI`Ex3A^hC={16(aSgS#mR(2J=-{s(Nb)5Q2%+j{@$%b}qQ=v7vLlm3Q;^Q*y zW-qxkZTc^^8AC^3dK@6e41tm#Ong0BoYfA++|&ck^v z@ixJj;F=D|Fk(`yOosZRxqYx`{Z5MvDaqB4U?yOV@B2BQ!ts37W$S7C3hN26P3$sp z{%s2zzI;lk`#fHL5H5~kT7=+Wb~2E<6+b(RP~ql^IYl0ZGD8(p0nzzcwQiE6_R%=T zoyO6H7Vh;`BRU2p-g2rKuZ|3F3j}-1+E&HM<*KeMT#)XBR0CZ}i#g^q^F@on`taTn z=D9^U=d;qW$}W1|VaV|6s%1U&YjVY>r-sP6nWJ_tfeTgt(9*5Cczn6jzEU4fiH?g- zhcj3xlfv)|DVwbIF#T}Uc%>m0^b14pQRRsJnrt6C@H9xEIdMDBsBwsyyX99!2|Fj> z$m)0fQ=7kb=+>V6IN09u5|!or)dOMJ;#BXL$>|>c1WOmpn;EB3JLfXd7dw@V{GL9C4?=|6&q!LNSl^ zNX8qF`AR%Y3!8RkYW zr^Hz(UssQ<(HmoT$>kJLX{~40@Nh!NO)OYb1!}D~iZcnT`(*dsrG5D1C^YVVe-BMm z+OKH!*JWBWKfe%Ur?k0`la!tpx3&{5FXvbLT}-0g9LZv#DjCO4sGIVV-(e$d(s(TX#ih+ zQyPL$NVKRZyrR*|9QNUk$5&drm}e1kKK{)TllLsJ36m+zfKt%=xmcF2uh-GnK_1Mx6MN6-y^aaAMn``e-M=`JB3O_ z8sa|o;p~N5+Ap*tIDVn#&fQ*^F_;pPL0Neheo;cW-Sy~_-3hUl!Bw_j~kp5yHlmMNDFp01!_OMF5es6*cv`-LE}1No>! zj21&%$k9+oyc6OudDuE)<;{hD_$c}&M6 z6!&8P@!+hZzQwq4<|EzVPT#*=&PzLR{7m`Ydm_(V0mElAP&iJX6q&XGxozgWd++26 z`P$zs9I%2NrVxMiyGr-W!TFu_@+v~ws1VDJ>#(?5NTL_~GHpq5@O~$-N?^O33atb5uYlH6T`&ss(t_9pe*LrE<=_!hcWC#~>1!gyKz^%{DHJL{Apq;^NY(_si5};+*`2(U6Q{$^NAy z6D2`DGF7tj(u~0cW8_5ffQwA-46#+c#I zrnqt0A#fKi{igOjna+IfB=Ba5=HqElC1fyow@o=R;G z^L@;^u*CoVu^_iXv3vzI)9g}{UTu+S-5&v2HXp!h$$q9d&&*s1ok%Q{ z+o+`HyIwafbT@D+i%1Rj!Z|DMV*}SLcj`{GCJH#0%`OV+F!YyRJS)$cRib-ff`D%6!q4=g-0y9Rnn zB}MVM;P-nM-Ti7>3s?LFvS(c@djakAd%O49=2~8U2t}&@o$lY_`k3^dvTCB0L32Ro znq1Yh*_ahPlv&MG2(|fFMVxx86D#FI6`N7h~n!RN3(Z_?;P^7&KYe za~!4jG#&64dz(~;{F?wwlR`3Pl{G~!e3kij=VUr#Mni@k5crO_n@5wf;TSOdTC)HA zE9obWs&uTTrBvP$WiRn2!W^E-K8lZnBJKbcuhe=1Djk|^c<3Jrc@)6*E+oy&@W)?;CD0bO&+Xqx1G@d zW73^wK~nxlZQ-}*?;S!3dIxmxnXYqbrj~37bN9QtMlJNoo775MR`m^>Z7;0+VJzPF z_AExK@k201z)+|wu-)!^bGM$Ft_@DyZHW9w>iV1DU^NYml3wl?MispWUVN?K)@5#f zhMv&*BjrH#_X#@1M@3{h|DA&wW1>K@bqRbkp$gLq%Z2jrj@Hq6}nh0u6~~h z*}ImzE)XOVv3_fLpfkyRylZ^d=AAqG?%TJA;~}kT^ZkskU%$3ey_ZN+--vmUz*FMmLnZ$F5LZtDOd-UTMsYT1}wm+7BFI-UkW zy=Pz0@G2da7bTe65fhL~q z0dD96aAqmTjDgjTk53>C8i5bWJ%ZT<1+DOvg!lxr@-0DV?65tRkU#3^J#!yu|C}=l zdKlt!Y_N@VxrBNXZRyi^Hpq_Fa$-aTrP3p~o|J|PlBgsTtMzzlgqWu?+PZ|>cr{q+{3Osnb;0zy@(B2sNOM~S0OPq z#ce5sJhl~WSnBx3XbXV=U%hXyMBa(umghmi&y%&ct*z}(PwEi}+ed6Bwx8J^#w{qC z^F+k8R9jr-jcc@x6y~_0p_06mUC6j)W+=SceDk8%UF{H3ad9}$mYun=@QVd6uDA>U z+ktFs)F`wvs zQ-H1EDOS`a#u96hk_Vav5T{kdE?3=F&Tpo#hZ$2vB{-#Hm(<>()Y`ha9%0wUSj*#Z zd)okLmmv8a2$@4(v9Na(+8x*^FS$hvF(UFLG^7N zm=C$<%xN-nIKl?gH`ioQ0a=Z#pIg17bW=I;;!x`j!73ESpk1Y}DMtngxR z@F6!bLS9kW!q5(+^s7Ba)Mi`saRW4OGhv~cz{8vD(ca?9Y=Cp~5k}FqqdvKgxWv)5 z*I1Z~S%?WXad)7XM#Qu)wj+}VMxhxwmAY7G&-o$LQd_*;ASPsPeo!MbGt(RnsqArN zoVz|!044{-_r1EtBCU7eJ&v;ugVlx?qIv^@gFCC2@UaNT>!z#G_2MOP#w6aYrcU7! zIATV5f*jF#O(?>BMx9Kf({;0wOx$OY7Hv(8g}mm;)7lfJ`X9K2wobt@)MT+cBwEt5 zu>G^uMe?b=sEcg~+e9cYlY*oUs&m7Lja6JzfBllum|TwNy%&;1}htzZl94IRnSWbUIk-f+fNSA{1#e&M|VbhB6GqV zU?BdswKUV!Bw;QtnXt1hJi~@(*M^|&;#&U4wVphA5)c%ms_%gu92`t)29s^HwMIWM zR}h{)h=T>ZIgaTleH3cf17r@gh&RC4J7{h^KVf!CN#mYpVsjM`UiX#JJj40xLI$w= zV`ESJutr;BZ1~5M-_+C*#v7Fou|DyqlOOx+*1yE1qKuW|%3TD>J?pj@5UG_YGILA)RN3a4r*TJIKy!OCw#+ zP`oVp*^f+2UW|Pr7dK5l9X}hx$Ue=$XZ`bOD9mNRgfM1S=wRvuI<`kZt4p*mlV=^)oDo=k%_@SgjD^Kb5s{{kC?;B4pH0zsE%PMt zGa+gvEo40r&lvZ{uRp~_E5pZY=8U|cFey8XK8fjDY>$3ixfh~&<2jsF7GTEuC1mkt zcAw|RI-CKw2nvko_R1i(ttEt!o4XT)_CLaKk_4Y@U^9@V!(nM?J`vGw$S_btv4*Q9 zEi#x(4spgFHo>EiaJ32P3sLlvY*<*$T3_QsrMZ8`@gWP}7$;rly}en4-4$W%)0AlF z+R_#}azsdk#6%F-U((C}O+S#%Q# zZ;)w#;ueOOM?S1kRT=5uwyU`p3@aoE-*XdlSr){(wXX@{HfS%l8*U{m42hMLFH}n= zjRxV39|QGl3BuR%@+R{pGmKyShO4|Mw49yaWQ0kKJHo$QR+1t ztt*WwgIS@tk%c?Sv3;n=Q(Zv+!`O;{izyp#98=ROOAp?oDKRvZQ9QHVd7j&|4S=(l zHFh93%Nxl&-D_3w9gkoIk4Tp6j)ki8Yy?=jFt**^p?55obyf#`jjzr!c_*Jl;4OyN^S&_OD&buQ>SsOurv$_V(zO1!BlDrKToXt=2Mvr0_;C zneOxCA*&M6hb`tYcQ#eq^HIUk#|B5axs$gndsfvSlkEE1%t z*2hh6IUxl^y>_}_`!pc+3byBO$F;TzrY(s!nli}XT}(~WO(>%ig4qRLIv2;48af2a znU~y(Gkz(yL>F9OZUTXvGUn}A5F7Y7ca*Ns#+j0*3VY`rj^iS40;h$T%U4%su{aN? zm>`cTdP$Xq;pOF}&kH9X-En;Z9cYcPS9Pzp@L2(Nl%-*5gvb=WFf{mE#*V2>>>6+{ zVA0D3cyW~k@IzfhC49#SGzBf0d)3u{F({72)Sj01;glqmAj9q8?Px23(^Pan;_7T~ z3F_Og3Oi++GV=%xJY|rH^EXT1ND^*N?Wn&6wY3cz8`br=QbL#3V%{=1@J831mnBli{RLWvH1HN)5j|)N4v)5;=_z!6AR|*jWQaTik2J-I zQi4S@_^w|bfeZtzWfn?5Rx}4DoM_}SJE`V3W1j9&tJ}gLsn^-5#yr!|&|ulGiZPA{ zxFS;E>er`OT!X2bt%s{j{8$y_)cgl#NdffJ;nK@Dm>u5uQz~tt?ulYxX=!PZg5ITQ z1aDU`*4_z$f3%)fB1>Ors}QN&pV_!E6XYK*y2HVf(6$% z>$wNwhTCi->u;5)`FM!RoMa1H5iRNDrhhn*EFu$J+t$q|n~PUGDh~5r)ACuHh^2mL zo@Sh0lQb%Wmsd#~C7CHUG2jQB%`unKT3BUIt?0BXu4bS0!%_mKR0P$E7&b1vD-$Ps ziecKtyo3Y+ejCV3bEh<}va?_43>wNowp5ty5a5Di>jpLnpIw%hH+J&c3%7Jo9GfsH zeACmHk|9TNuJ#Xnc$3$ZCTf`(=-NHD4W5V*(x9&w62ZTrBfy}ga0KBECADSD+-c}m z`z&bR^Cc$)yO;}KY~RATGBYuabN9J1&<2~|KK;`HVh(XD=In%c3NSP`GK$6dXJ&0C zx%GGOp?DRT1RXXabi>t;u>)sr%2x8k9F2N1l`JSa5!}pO?ahuA3!DX$8fmM*H{`4w zZQ)$922YbYy`&>3>2iuJJqLiyEFA&1p0L%*!{Ehc5-rTb^Z8fJr8tzT5VuMZcV|G* zn_sb)8HUe0wu`R~L11rG&(Y9iK9SbY^dPyZtMo3N+FAFi;9Z&NbF zXNG$nGcCtnpry?#X%|zv(Fm~OX}ZMxX;vm<7`t2vSk)rGWz27e?X@<@WM56?72CzOl z-bfK3e8bfG;nUO8NpswDk#C!r5+D`!AVi|3$$WVss;z}LQ(0Y6v2<)xy4&A!bX&Tu z1%IKnEA^F7H>{cJkq~c+wo_G?`Z0#Wgvi+MUH<3UgSx-`1EIunv5Dv*((gw_&c*aB z+?~m%d!1>A9~lK}rN&9&MS5Upr#a zF2EE4P$~wva@lapQ*?ajk&vRGU3STx*Js%noR>9+-1h zO1z^Ch@d$0Z;kXhU>CmtKY4buR8mYtxI!8mA9;DDL3g->ED)GlHt0?pBaoi~US)2v z)nQ(Rt{7#>UMH}8EjfTF5>6vFiJA1PD&6?T&p7jq97R}UyOB_ zfQb01JrPZV%nj{ZPm0@iZZ#O~_^yo==GpQvBC~l&)Jtxt&olub{U0V?K9mp1(I~#0 z+7l99-ZDxWtMP00+4(dqQ4ZoB@1K+04<0-?(#xNXGCkc;#C?(X7>?}3UYgmST5UP> zgd7Uj2?-p9Ogv^}0PWrh39gHEyA%{mx&gf&3O);8L^nKcVGJS%y{9M04frnt-^nBT z?A0QZ%wb?1l@-LmW z%Low1k$lX5xq;mekA2E0#Fq!cg2*y5|~!@G1i?;kdq z@kn=4O^E~S6Ly!yBOm{X_DVhL$~R#u_ggA~DuC?<4CLQS!KO_@&0<24U-t8H1W^sz zyq}qzda*7UY*`nwpEWY)u^yN_7_j$_pyLNlKEor$k`uL3<*bhEBgl^bGk~}y?$W5S zxjZuyYes)u{V&UH9-5fbbj_pm4ndwXY3-GO(N=PA*q^%rgz)H_Qjxu{lXO-KIqvh} zS^1!j_wPnJ{reXG?g5!;tKZH4XJ6Q#f&aUA5{}RU8SmUVu4bC?+aGr+*u4SxdkDqj z)NRw6HlMNP+-$g$uD8+ZfINAun0+Z!|BTi30?uw;Y)sDjH+*<{All&5soygUS{W{V zwq`?4P&^t{hx38qJ$(M}V8xK2?-5R$dKG40IU=L@`!+G-Xg^q(k-ktOZdu79~e4!-)V$q!6k{p15{@#33*IKI4WlkgK zn;t%lxmx4=^`w^U!Hy$;M`zfD^d)b_dB8fxEQ>P5eE*rWbl_d68z)OIIn>6_waULy z{wQ+Jm+Nun9#wzu(+A=a_qhPt$gp>XuidnBfpk3ZgTnV{XK;BbmA9ut(;w3xHzBU< z<^_DuICf4hX?ibNP%Hf9o+*48%=eZvyYxzxTuAk2OTNCh`_Fgq|Cz2>Z;(gYzkRw- zYIN7+*FxTEMwkKaSIYN)oOb6icnxYF6i?Qom~nP{(d<`~hx2d;j#K;{xXp-_L4!(7 zGxVBVxOuQpFx_vK9bBnuYBYo3POYe*t_k6P&@J`u{hs3cp83@(=+ImI;{sQ+y#3(4 zv48Jd@F!JcnaDw3=5zM2y}ovM%>$WOmSmB%-ao+6cFkQsOAm&Qv!0jLVWRxo_e+N_ zdg-{_ZL8d`Q|=D8U3E_`6*@`O0%d*RCks*+Qof%Du~=*YSb2luUh`s%k;dEtP6Csc zTd3w5JHz9lpWv5Cxv(+BEvzfz(RM4(_%zr zHmj3kN}(LAmkm`~y(0h3+W9g^+BK^qIGd+0QdGT(17<@iG*8s=o+Rlj!QF1l(XnWA zT*W8#&6}rtUCSy(D1x#074`H_hX5b{Pm~NW4Crg8>C=PWTh$;)3lQjaPtY`ZXT^wgW!BI8L7NRBgo+feZ{n9M_|fKO+90BksN; z%z(!NYD^x=7ptq=0#b9Xb8aG-rC`!>W<%;Iu< zw?*Oy7>oUEr=2oqqUml6w}+AQ-Xz;OxM6fs#at>d0KZEj_IeZz*}E=}>}hTJfC4l^ zkj)|zL~sQooM48ot-Y|4+nhs({z)f*lP+bqG7D?a{WHbf-2FqnAmr#JDY6OmHR69l z>}SSm)xBEKA^;sAMR)qcUP3hX+n;4EgH4wh)K^7ij_+8B=a+W#qLZ2$S=7t@h|Cm` zf$8A`z>aTfjZrc;7d9b3@AoJUtKZ^oqBeNRw%=P~OWCe^Rh;ZnUOdbL7Qweez*!Li zV0LeRe^0^ODHef8Z(knOtpN|SFY9AyZuJBrjryW<=fczVv$(YM#Eeh=wY(kYfpaUn z?(@8to5JbP?lfZnVbt5uimfUOZam_qMF9B%k{*InfdTHN(i~{qm47zt1~%I4Umpx) zM{qB}c5n3O+u_@;$r5$}y+|OmD17Xg?|($?0Xerb2|K^EL`_SJ9mi*-_w#{eIH!mA z2?;P*>ATjbhU?0eYW)%=m5Y*n(}w>&;>+$4UM7mlS}`den?Yc#f3LT*d)(2F1)5kG zp=t{T81d{DeVYG*N?rZ!Gg(m+ao6bDJ z$+_a*HZv**cZ2=LkL*W%CC)N2<=lv1J4~$p2Zz>UVgf+q*XD?iO_Q<3joHfypP7rT zIynS)^DTcC;iHgJ-O4tJAZI2uA!Q(IcKFQ)vfNt~^T-}1Cgy0I$Pb|e2UR@jJ!h9Q zI1kp2bbTF7i!$AB`kcL22mG4Pe;}g+fnC{?;Dt8y`1XYc2KM%I4``u}Qe3+Js7KrV z7S_ua-dptd#$M=|x~4M=tlRG!k^F-kCW_ai;@# zQ^KO_Gri|*85j09a@7=DygYPGWvUwvheTUldbkUvHhUuF&J*=+gN%0;jdHOF7f5PC zfXL?>6w8vY*5#&Ri7O+3z{&L%HHHYiRRQFc`WtnJ zU;JYM@Xg0B9q+B=<%)7LGyBXoz{Fo*p|ydD0V^M}Il4G_r8XK3^sdnhbwob?MClMgy3VoFPYHy|pnJxvp8=?t+j*Kz)&x%Nt}<9gy)a{QgAg z^8mQV=y;wR#=v>Y%OR|QqwIAA;shYlK1|2H9S(rnt(X*1Ex>2wLH3Ij#c{P=yxu$> z!jhIB1`^f(UI26@7XWbj+2CE+eZrUPxQ&B@L%GP|j!{Odcky#wbvP|{^6~CQZQnz7 zPQNV|`B#@Zc7UtJI7oWmm(<^~k?Uf`i)9lO4Q+wpA;)X)dIs5;BrbcoKio`xlxu?! z0ce4uL+~6Vowqon1pScPlU7YNPf{1&8l|u4?3r@as_#uV05G6f104855%_Rt#(^A& z5}NGCqvQF1@Ljuq?as?f;Mc2ifku^gfz(ypvO(4K0r@2t3>_`)6R@(&DK$yxl>-M+ z%oxThEI8fa-TYVx!YXR=YFwWrBSbOc>^DwN)pK7J+*` znhjKBoak1Jeztx3&|#KTW?phl+SPq>>z$YN3H~=N2xIYH#zn7tsZ*G%yIh63b+BKN4uXprhQ$cgBl481@zz3jj1)_<|2ufcDpH3Y5tcx$Gk;s!e~+0d``2=KqXL zms!adB4WBV)r_symrBNuWiEX#C1&ICSVFw` zv&>#K(0m7)9P=$qh>V;(csJmK)v4>SRwiCW48J~kMRJPCorWy=(Ks`3@jM`R-o)+p zm0y|YC=k+QO-SSh%B1YYQp>Es`0%hKd{?`Z1gx>X`A~WsYnIKuX;)xYrBLcd9#T~K zTQyqqp2IkcD23JQoD#j$Z^)BFA*lv#csw|XX@~r69Y2`URT`$1C3OklK|UVGR{*!{ z4Vbq%@U)h?3nyaCV#bZqkF}F3f26I)(^34INPC&U=d*z^h)zn-OfRR&{~b4eQXz+m zoAM<|yV&HCssjNba^PT;UGs;>WKM&5TBXl}TG80pwQSpUOd8CSFH0s>N-oN96~)y& z!lhpTtUD-8BX{gOJ6Wu%k?3jixJdmHb~PZY2>BUV-+3~8tPpEcV1gsttLuSqpLx{Q zCaeLv`Lo#e-}v;``3Kz>??_xP6CqFRnM4WU$FNt=yNppe4kV=aE4r`D@FwQ{p?4dSG?W^wbJ$+>AlnG)aO;7o6xmP%|@+p=;*q0H6~P0zE*$ zi^(x?>Rt@^z58v17Q655wL+xv%k4V`!am9QiIOT>KnsB(B5eDCVK}qg$F$xtz7QM9 z2!O7XYJ%vhK@584wC(RpsDb#E4DH3Ekv=8oeYZi4CFKY6fN^eVUb>&NFuXAh_Dr2UCa--W%KFS31V8?YZZ4Z00j zFmS1SHy61yd0!7Kk4fH~M$1n){ED^P%&q3w5A%DverS}9&&-r&5)T!Ke!LsbXY=J$ z##c~0xIa!c(Eq4YOEt6CEcomGDZTU{@P8dHnOq2w6TbGpN6q)l zI}rCa*o<~B{)hpsS~Za)_kXQ8#U|w+&g5*^SlBKc_z&`VrT@F{e=h|t21IY)*WHiz z=>Nw)qaNTO$dhVE7r1DH6EE)i0GESzcdG>PF&N=VTGqynJ_<>y)%-8!-od2OVd?538paf37{M}De zp)|u9xwHV-13e>R_3eA9{x(jcUf31-oZ_cf0DF8XYI}dHOho z`)*(h_Pz22kw=}a-t+yP8Ua(-=W>eeyO}2qEHXE4^cUv7PSzv2iE=UXFOAp9gFZ5cJ=|yBC#$>)iV! zI9jc_3(YtxtxmrF*G>$RnZenJ*Lz&=55&t|juUXbe=UqtiU$ZjNbTs*eTBl8vN>;i zH>N$-3(uv``%9jHE1fyW#^8Bm=!h`>KSz`M+VKz|7l4zz+#&w=YGV7F{#Y&#Y9DWlJH z(8w$A*U`{{O!yz7&KE>wc^aS`83O}#Es>Flmav{w7*QvQ+3ov{(D9OhObx!_#zH0! zO6*iL%ZOB`(>uCzlKtZgz|?}w0uYqjWbh5rMXuEZ2C{qFdv>DZPzViNfYT^E{o6XV zQsvZuFG9C+<3beNyJZ=FqY}!u`B^l71eU6Qy3j}2zwb6b$!#p0HtsD=xX6hN8|Rv= zX}i3{*Inj6)JynHRxweL{F+b3&T7dXb2l)(J<9lfyOzyje$J5VuzjI;zMYCsz1cv{ zs8<07d;DT{A*W6@txL@;@zZ=?PGA&GI}4yF!J=MXzvhqDU(w`6L|(n1*x37~Hb6Vdt%`t5uz-QNgV?={Djq)3%w+S-Mf{AJ{Oh9`nNkh~!;Z&|wWN3NH>| zn}ad6S>s=C|BX_~koAm{wM~f4@N}p_bZ`^hdngw%Jb){fKlMa*U^zi+Wh|`?-EFQ! zr@BReD={E)$L^;sEznuC?}1TYBQi3}GB)02eIlAvR+4f83qlU3o&;`r^Pyei(F|In zADAj2XA&0b586eFNt`ipH5$+Gs(i!E(;UuCBdR!9(jl9jL5IN1<`Hil*my!xD0E^( zxzmX%k8|T;h6AY%@A#wj{fdHS**I+6cq#jXyPLDo;m~kRs!9V3cB38I2mROYA3a0= zFP}?x8^!RSzRBC&lFMDi7}%VWapx3NS@Zt=NuT-wg7-oNxM@)q$;EQx8v-vsOtr3g%nA1Z#*jWsD zAHucGEhz2F5V0#WQZc=Kj2Kobv5crU{PakWnV^!pfA>+d_EgrIkBVF)V3DTzx8zS( zP%CbQCx_+YM?Ht8`@QVZ(S`>Kd>RILujc}?8gK*m08!#~_1%y5={W~oCKsvqzJ-J` z1YgdxrDpE}{gN4Rl!MSD2m7i+naI6|V0^z>)H#`Y2Atz%=Mc`qQJq@3AlmC{nqtL` zta&dZ8Z%n>`P%K9R|4o>A1jVG1T^HXnWtDjw5I?oI<=(kB#FS+Yf+3HRQ9#nD7V@9 zcbthM9}zPV$WvG0sAUB3W8_VWf-DiL^<##`^-Q=;}&IkGYom$L{k$x=CZ z%GFzN6}t;Qc`t?1-MtdUtIQWSDy!z&7$|)ZKnOF0-1onU3Hf;utuO~zxoT3nk_m@)wpvy5sE23PyLmd z;mbPq47}a=*<7Hg)*^a^K-ZW!2EH34C-T^}J;WqMZWzAw!+YFXE3^Nt;kD+^ z+D=&Rrz5mfAvsEMRv-zd7k33;rIy0UHuioSMEPtj;Bs|At zPYQAI>(lYpPOI_RIb^FrU^&1DB1vR5%*En`rR9MU2`HlE_exG1W(+#2Fx&Dei(Yj70 z?FTn6VpW5YL?f@&p#neL1khCe<(>_1rWs(DGUu2kg{K`nT)YiEG?Kz)F1Xv_R}orF zx3TFsvxG$aa_W=w)F~1T@a+YQAR$2SYYbpf{uj5l}FBcDlLekRe$E`bn8S{`0jLArqcG~wA) zcYkDZ4Az_QHc#J7!ERMmF!?PCwdsUAE&i)plD<$|A8N2;uJz;`E zcmS6N%t)CH+DMZzzvubl34FVZskvpttOnmri~BJ=v<{;MUBlypm5|VB>zPvcaw?Q< zPD3RjUrm^`+8$Z_K@SveM_mOc^CjAC)s$m6Ag)zQ3+u#A`SyoVJ!(?Kg(?;Cd5 zMgb$GfGyN4=R7{wa|PmEW4{YXvhb(Q>;aOA*OEY65@RLHa9~^-y{eEDT0=V_acRkeu_f ztY0ES00l`=BUbJb)i`MF)H7y2fE^Z=M%RS64oU$c6Pn`@Y<}bon+7$K z@-wWoq!{11^~|VzlQm{11R#}WnwDPR(^q1dJTM_OnOptB#unwoUq>y9W)~nZzxEVO zzTuCSo2@b0qEOf>F(Fi8`g#Xx_%^fP5WEdeFzUCNc}rngeA^IqEDS}GFQVf%!d61{;}_P1p8ZU4l25iLbp}g>UMul>Ryqf+viUW18~t%k ztAO~SmCM-m$-}lPa$F)rbnM0fnhi!yLWMioYlV&Iee5Dr{NQm?ic67{Ntn zvvUCm?_A>=GlE0RE-Izu%4?xRvD_5V!7;k}zlL%~|rQ|11 zUpHNthde+kr(&{#BsJ7!7fO*pqnvYC^npZ-H_i}m`j!dyOah>?NlbCcE6d2y#(pv` z;8YsiYIsS8nD7T_^IJv0Et7W)4~9xJBn#e(ozE|-dZfQyovn{Hx9G)=@R8!|T3UP& z7a$C|iIq$b-h#M-USP?Z4Bj$FHjAy)o&Zs6(v~b_YUf(;aQ2aFE6U7x-$%e#V0T6$ zL`uDLtRyi}4t*gOF_Yj1!bL(T(_T!qks$$)+XF1efOovwSo(NyxNW>#6uJ@#o<$>r z6`+wsy>bq+e9wGE603~lneZlfiKQ|-ha=smfmK@BkR;3tV#-E3x>WPpcihTH1p|c# zD}jxWz`z)_w^!d^oilO^1zj6~*x75{nKSz3^W*zz{7Q2QG_}yP#2H?lB|DmRS!np9 z_1h8<&qrT?cK}jyFGf6E!`qhp9`4ynWatPo*Ky9y&+ZG2CN^2T&y%)mbtHYC@X*v% zn}gN#^=Xkd3;kEV9a3@QyftrY+;~8I@sq~piXl~AS=o+v?Ni`OyjORa7b}fJ#ePL< ziEZV!&lR|?YLXAjJkmXHw7$hrHD9dnwR+bWh_BRW)uyaBi)?u5N`#5mQZCCR5N)R% z6wsaC!NFXXAy0Ta!h@`F7#DF{7%$ms*O=S%Iu9?lF@c9qcX_Mba+AHnj+*P4b&}6o+$;uQ;hoCAj9-I-BeD9N&4KOKUtAB*cmduJ9 zs)3TMCqDF9*pW(Un>DyL$Qb0YzCUK@*7`Lb7_qVT0p$b%Lwp=s+j55etKncwK??PZzV=SGF^zIL0x?Z1xygdU_y9q2<+L|in9XD6 zHQkzd@3Gx;dyp)0ldB1Y6{OI}FgcWwlvsEA)Gn&7nFcnv$ym+a>NkSGJvKtjZ}JGJ0fP#2!fX`__Bd5$e=Mn5e)?)vF{6!Jvg4Pugt>U^;ou}=2YgUWFKD?YnC+!kwFyKkroE>Mi4L4}I1%L_7 zHpgtyCu;W;cnNgr7+UM-47fR4r7g)!SB!nC`PiZe5PfKzm}t4n^q0zjAf-oN(YG&7 z6oK=81|Q?!4ltGr|D0x$gjVbh_|FwaPLHi8ct;$;o8Ugh-i8L?N5UeM%a~LltCmxaXVgPIl2%D# zQ5~yHvy|YGcwiNATitf?DL~uV5F{p^MpoOwgEtk@s@S??XcJ@#-U5G7-_PV&sQNhj z4o@|6CBeZ-y{dhQJW*jgE;v7&aFQGHv>7;VeVIEz{^Ey2Gu!5_wvqYn4-wqFlv}Bb z5k7JD$fcF{+rRK_t5iQT{T}}qSp(f7Yc(FcOA&jm=GQqUgPlYLeOJ*w6~>{l&NZ1M z&15%|sGWXZgUh)x#K|R*H(trJza@_nZX<*LRI#yESt<>vm!p*Jm|t;$j{uhxvj*P4 zBR;@^d3x9%P^NwL2?h>Nt38LV84i)Np;aF~)T)CjsG*J8Sx~ECD6k4%ASNcgn+f-~ zud>{(^n2Z8{ve|{c{^t8nZA5@Va*hWJd=pd!h)mw#KO2A)@wQpzuW zKySYVIIvWJ_^BCa(=r>(?R2)@N)R7M$c{OaU4%=kOp@d3DLM7&j=Ffwo&`!ftmLp& zg-V2SqsE81K!*lJCXos>b{&}U*>IRvr&G6B5_SV2>aeWi4Sa@G-Ez9dqEjak8Wk_l z??f~0b?w-4yP3melMR1j_6Zj5aR3vRuGta=E29$pFlH?RS$o3=bCm_a^FIE zP{7M5KQB(X87-gmW|aGTnem`s>$>5s>saL&ankJqebQG!q>{)rl``~n^~mAJ&MhC- zKI|mpI!;xj^zVDZ7Q^%f&r!p@t`P0T{6c(N-*- zYB)OR+uOL;hVh2I#^`2&xNTc7UHqOCSMazxw+BtJ3%y+J>$7dZ6fCtcMBTA{p*J1s zO8qvWl{yJTo?RzJ1EfG;YsSE_W(om$Sj#z)?aF@zP@#t&skPn}~wA>4>T+T8sU3={kTkH4J zEo3Eq^2-S6S{lGZ%SX?ptqR=CcFN`$%|Cz4W!>=mXyv*vz>2|QOEO9Md40*+^ZcC3 z^9I+&fN`T2z}@WCp5!_;muQ5& z4D>uE!2(E3+YIf|WRP(*49EoOM%7qQ2=ln8yjcrL4IdVP6>)tN)`rToX_0ds3ujUR zBdg@&3=|?f9CclSbEFoV@x8RfczfGlzJ2`%FFa*v=YO&Ho>5I@ar-Eaqs}PkID#lu zMFpfukt%|tfCz{nN+(u&kzN7`jw31pv7q!K2&goXULzt#={@vF4K<+$0!i-g;Gpx~ zweJ7ZUH8LX?^z2Ml9PS*+4WbR=h>E=A$~z4~c#L~v0z2vkSd=*TP36gNUz!PCc5I0`;)3o~2iQhnJc7|jkSe}X znCfD2p@VUx={pD3-IBIq?z`td-%ExKQeexKGijJ&<6M4|RpX($Vt4i(zDa{lHKlJ? zQTkM-*)x~5n5|?kB^$jd3nMRNx*Ym&a0|KkWY~k?_6MfK{aNUYn`fj7UU}b_Kj~7m z3sz>}IP8Ron8Vr{ipM$oX8Rd?C%f$;XTbXLW;|-WTWPI*s%2+l-C1 z#;`RXAr*b6q>wm9QR?vUNEmM{x%AH@ZtlcqK{#CKo*`l7nJjTR^{#4mf7+5fF?*Vw zW-yf?OY^$5SK^9^&p+24&z!i{T-DI^q<&b^=NtqW4dJiIzVT@?L9Xnemf;7I$sb_l zfnPswyZUbCx2pLsl|A)}OvSRckFmp;M-3L?9-zaXm86Vs2$uT|YH?h>yI z8??qv`%fteU7U_z4C)C3>!M)`iDp8vWqnx=7wA&JK8KBv7ps=7!wPZMl^Mij>Vj#Q zf3fr6jnBrG0=$dmtDZ2kd$MDGd-^`LSj&)%b25WH_d^&NwmF;KDQUH>^yrmlR-G2(B#H$y)3 zN>!4)KZmxm&$o9+rnx2{Rpv^n4$Y}X8*LEbAO>fdjZX`lFaDtpm zMF0-n0Yld7G$p_n_?a4&>A_AQSuI2G%3c(C@kUl;E5DrE)5dA<`=;0I=;4p_683;& z3#Mr+d8_@WjLEXSXLs_%XCtBhc~|#oZoz^rGCRCmpS%~a&;Jlre^D8-PvsOe5>L(< zx_zB>rOPd~RuJ~R)O$9RE!W}}7sQ`~>B>R7^=T>_E&eFDaKC^J5_cwJs9^h7jey+` zdkqr&fy@P_3{p4xkT7F zS~3~VPFV^T&R2fzMWU&?Hj7L0ppx!Xr&~3GB&7HyyuVU1r$e{@UG-5Y9Kx=0=GM*i z0vZXs4RX#4sPxP%D_wbiFfppB^(g9Qw37JAzo0%m0^78LSwpnWo5P)y{Gi(Vx{8Da zrQfTL`iSR(8C!AP=0mOnuXN1s%1(19TgiucEbzSPI;z$O6-v7f_)a;tx*vyvz><_H zFZflAHrqj5A%DY^zk}$*P0Re+#dI*BB^$Nl6p7hRy!?|K_q|sFLR4TkAw3vQ2fuqO zN6a@j3e^Hr+8C9?uVBIUH2lAq=b0) z7z4RJ$ghHN#7=ZiI8l-dAENFR8mig?I0VZ#cw1c<@^sc9ySvhGu*cQ$QyNUUP18d<0 z2E{>=HJ9yclq^+tCLoj9WD`^yYCSA(M#%V5w9>h0r8Z+<=PZwAU3You_4_v$YrOa` zbX?gdi3`!6HNDNdn=2hGpQ?l{GNZ3T;%*i7_DsFE&dnhl-9>%kHGAb%?<^fP@q{>@ zk)QH4uP;7pP-{O5W+G;UuMO4G%agnBDxmUZzNf0`kM51E}$f-96iV(Ua z?1>uVxUlAMfTaR(z-I5nftIGGu{BnU>PXO}uJVz_N%_xYoV*34qI`d@zO;o4d7nQhqu#)Y!lbR>zpFZ9591?a5Ax2e6bIh?Jmb1J?#SCx6 zs()6O^n37#@hEJIsIQfcv06aGo1j{6N@wf+OinWh#w_%PjVQaU+zO^o|Dng66h~q; z-x0RzyRN6&CGLWz8<7^e*;k<-n~N!sYxCm_UNpMqmI#sFvIdN}_LH2480Y#@_3cT@ zh;^EpyxL}A{&LUJEvbxqg@0Yf1`pP6KVZ(|5O9ik@YuBn#DvmD+wrE3LB^R;b=XaK z8akpQO>Mh(iVigzK~(YN3*wZYK1}{!V-I@GycXz5=r=;;v?}5gs;hF&yl3B`uP=}t zz833AB<6HI%dJ<5}$7b0xj+ zW%HWVz4uJRPg!jbS5Wo0`_MD_Flw*|4spO1%+lt6=``F%8~Ql44F36SN!-lqB4?`k z0Yf*kh*IERLk-bk{0mBAUg#LIaWCCZswFC$c0`l>8sAGeip8ZvAjiFnirCqZqQb}X z!qN@@!Sy2XLiptfF6zyvC(k%l6lD{=z;|K$!vX;&!$hNZb)$49BJa@$rMbt-rgEe1 zl_c<-JlwUyYQK-;$;ySkv-GSS3@o$^Sbl9ZQ#}Mu-Ax^BLvZ78o=8Hpk%=O(*FvT= z4l^njT3g!;nVc7OFZf=E42)Z0Pl-rZHcI%~+uL6md1*f_rj!^e=!Xf*$4?~=%zI6D zI%xMqaVg^XPSlazTkl7aGc#T|L#>@Ye|9RLBVW4`l+LDl7qsMU<5 zoz}Un^jb$RL!l?9tcB&pw)9{iG>8?W^_&8P0F1uQXk&3QB@UzhvL zj~NFl(ziU?2`M>z$2_@HPOJ_P6?`*OvpcOdipo#i_0%7qs25}&kFo6P@wM}c-DX(V z8#iB}wrH%+*{i_cN1S%@xR-4@QtB7)c^Pt~c$Z&p6D`o4Hq8rPOC|*B&0&x^^s9F_ z5<|5#0TZ&+NghZ;@n5_%UsOwNe<7Sbub4Jbqfp8T(hLm-ut5hjgdmKl1Ix&q2JY-( zZ2;IH^fF}|qbC4*(|a-w-kv1f6GpjGCNq#nDbnV&-)OOcBsk$|EF6Qo-BOSv9#{a1aA&m(x{pKP|PfM+{)<@}|C&Or|6(q+c(i%oPR_Gkl~UGv{qIC;Po1N6sE0XohdI zk&bJw@J>lARm(erdZ4%8u4wJk%f_|nmpyL>-CTz5+{l>Xu$D#BxLgQ1rgu^bO$qhg zqK{`=6HMz@OKc0p{05_&yDdo2105?t+%5{f>>hpP*MuLt+!*6Hk}fc3Qb2BB4ae3e zpV~3V|M8=c+{$PCn~LjcJDJ{Z#vQvLB>Nh|Od6llY&%2J~u_vBb)Q+zM2!>cWyd*2&3E_2E3&cb4t!N7>h%3D5Ia)4}MDM$CO z@=WJ>yXZgr$jtld-NWOsj@h2>_iv5br9%F~D{}$(k#Z7qu8lbdyeokA)J0YTf@$`M z3d-BT)YQF6Q@8%(!zH5WR1v7SgNjT_Q3& zdTym3@vQr+`~b}j2yodS7qr)rkyhur-YxB^8cBB3G?8(iZ`=QDVFrbLa|^o?aV67V zA(4Cv9B`2Uleei2k!|GS)xR7Z(kna{abG^?H!-crN2774 zz0#L1)6D9_TO}A_CWxNh&CYR!XvQZ8-TACuM)awZ3psCj!j{WY)qwf}km*Sxx`G+0 zc~>zwT*ZDoU+7wldruiOquUGL6Uk@C`kS&x?V<%$lD~ zZlK-km+^Lfbg_2I2Srsp+A?^54Bh%7QhQ2cf*a3J)SS& z3-~qa-G(x2;uZq4uaK$GP)7MkBCp{t@!36mi2XqJGgJxnBVoRN?vlCo^J{?WS* z=mJZUfB=Db8?HymcwNaROUFo*%!@}_Ul5>{X77-V&NP@1p*KM0f=vK?T-IJv#?ui|qVrLql#t*2dQuHKE&Is9g>)wtA1 zuCKr2ZDV}tWdIcLC@&r0BF$JNhOIlH@$~9BTlM<8uRQNxMH=%d%sLAI!T0D z);x|heJvfqH0p`3X!eyoXSrexldUYM(V{Iy9%2e-!Qw&i2M~*BpM9^VTrwFD5u*no zDf(K9pcpG!3!SI8+YFgH>8RDz?+|^MZ}Fv{=F>iHIQW@tM4!(Yzx+%hX_H)pgY0Qq$So`RSI>xRqw9BxsW5VdWdMDR=e zAZfFYIh7}yO3x29)oAtXiBnjz%>pq-OV)I{2ct0C5d3iYfTGKSEbrU`jN#OL@vgN6 zoF8RTP4v)5Jg@(1?(V4lk~mhWbuz@67fH;w4W-MvI0lBU-$;u|8mBC2J2*IG+pq_9 zy<0WwJj0lG;dFUXk*=UaY6mad&!O@>F2VT3mB|<070bFlz*_=@vI8wNh9etIA$n?e z&nO6a)1*|1BLQ8&d;qSeMHP`Xhu`bV`3k2e;Iu5j0s@$K zmxA_Nd&TR^Rxj0TBfUc0tjvRSYsbJZuos+LcHG5mW3N#)Fue`o6& zLds+31dxev(2qbqo`Bn-dZud=SG7nrvPk*&UcC>IVIs;-v-*};-q}V&99XG z1r1J^V|Z>m$^1je(|^X{6XT4Dc0-py?{j_v3iWOne&3bi_#dk@xmi)?Kn57 z=l2whbdO6e-@+rYWQ?z0k71SP=3+|BG_Ake5Z{w5Oiy{6(|z0b0Eh~b45>>x*ehKZ z+ZmzinVFgN%6eKf(|=IZR}we0t$L;VX7;(pbM3vg4K4Ze+ zLpQ>AQmWcc_B9Zbv_nGlsjv*&%9G6tW46Kvqo5kG^BoO>cCHFC` ztmRXA7#LeQO4N9*LzKeH$5E3mMA^;1VGuB^?O2->T0C8hG&QH_G^Y{p^a!MU7i{#j zYRgX*+Sg77Jk6Aj4Y<1BE$to6F=1vAwjaX|CDy+-;XQ%#jT4S6HVLr8`J=J5WtPwuh3l2A(iSVL*Ci9S@Py;#N^s z^Az{9*6r*z&HJNlExt+H3_Dhh0AI{kycDd^Do-gv?}r2Pq1GviPRnvtPMoQ{*tivh zKxnd5{}u8C4jodON`AShkQXHTxy6KqN9lK(q{t!1Wc)EOMG9guv%P}eFWaQ7SDjwm z#kl5!feErxq2*t0TC%cNtyfjAoy!`SWA;jEu1YLA;};Mv1$|{o<+5Ar-T?ZdC%vJq z`h4)qbMI9!0mQ1*+`Tx+#gzS>BU!5%#$#PXS<(*`{(FoA;As%f`^#NQMTe&57h%n% zr(oei3}Y@vl}Irges${TplqS+ggF|}t;SSj=nhGf@ecBIe+tC))JVMWRS0)qp_+YB zcI`Qhkm!SmY0Rq-dJMvQ^L_AD9eS<7f3mF_W7BZ%oI>pBR`L15?Jzeg$Gq>W z#jUDTd4~3g?#(+kV(=&=CH@(T#6rzkFyQu;^_>K^^InQO1WweE(B;Qq4u zyuN2!-dW4;qkYOq&^m=C-1hArek7-u{UsY)WxbD8nF-kSAdN>b&tNZ#+S^xB=m{oT z`;^YqKRleZ8rd|%t7v(jls>#M!_H^|hy*JSBEH}12SNcFwjO-ThtRk1Z;X47$ z#!|*HIY%eEmaGWOb^3gUyNf3i3zz`AmtNp-4TlyoXF70w?cBK!1tIa3t)@`wYkg6H zkP41FN5tyHBY2ZG3$zIUe@cx)?B%a$&n>_BZJW!z5s0H;Zpp+v>1CLU^z!#iv-n3V zKbA`XoN|;n59v@<=f@AUy(HeB+o#+xlGCN9pxKLC%(CF!M&>H!)B4vFL@9h+z5zZU zKqIE!PnmoT3Ut5z?f9{U*`><2=xZ;!wvF>o`eA%rmIhcrl*R2*sNX&dqzBbgJ_=&D zWqK0S-6Hd~5|u)>=OQXPxBHkaQku2(+kYA7)_>VAbtmt>K^UMM<$GEXe!r}BI zz=ukHYzxCQ6}B+a^lAKZKUKX)s0lN^i|<~Gc}2wqgvd&XUlgj!=F_|iNzx8M4C578 zhmIu;w|0#BiR(0;I}v-Ns9>~+m_!1{j0-@{HNp0muNZ+4dzVMw5Md$@(yOO@yzc@^ z5=Ue_c<`Xfn^IKKGre1PONX@v#rl+#YR+D(ph(n}whTo-bE=gQHBkhTG)I5i?GW+v7%|-=3{x``9eLL>;&8q+#E|OD$ zSI|YXYfjI3X(~Ia-r4zhjiZ3iIq!%v*8?D4D&=#?&!R4l^TzzSvd z*yg13eq^_by7;wjv2ZeK)30g}xjV(Vn`<(+^QhNt>x7a0(yNmI(o(=@Kn!!G>lDYo%zjbgr*X-2dp!MpqKJ>;guBRZ7 zsBJq)Ml1CR*#WhG6F>HTWIfD%w^FYBat|dKJB#O@dc$c9_CbcOvUx0 zwJ1VF%-%BQXuR6E4U2lP&#lk0WTd3jqwiMX#M>QvOF7M4y5C(kwtQzoDx26=!Wcy( zVA%0-HO3jivPs6)?#-*m*dt)CK8RJFCv*FyHKQvJKii*DxS#WbpxTu*662$Por-~R zwtCsh+=M{aebKa0-n}H97PW}-YxFX%#tM70SnTZczSXsz%t`$%ZN?#ZqazAV(h?aU z9#CwduV%8G3Yw0``>a50Czh&VRXVt(mB!v!hqgdG!`juovIyV#?md^1GMCvGh2XhM zQqAjvi3rOKI?Zo5c3a#k?bDWBF{5L+sE7vi$4P2qoU9bAM0rImBJ(&K<_8Z54~a>k ztV^8D{NEy-YSSM|^h@~dR&@#%^m+v*K~ArnLejs0uNqM;DrEG42aF65(3lE%H=~C* zfvJ;Ba7$yU`T@7B9xISc%cjNLK^|{K#rE~B3lAb(kBHHR(%?b?j;7P-I8i<=2rI(V%kijC%!Ie9jdn)wS};JZt&8Gde|>H` zY%21O7P{>+Brj^;1D=Q{V1OT!DW;8ZMYLWz0TNhV&Hm(`&^80U@RMEzhi>fgbZqoX zxaVgbCC}_%p0o?;CXmPwO?PPP(g}b3B>kCZ``fi)lz^;W2`_k#fCm=&MtpF7Y&kf- zVVe7#3fdesA@cSDpJy;&TL6yI^0j;W^K9RbdF8^Sg;=fAk%f%owQcPIvqa$d=D8Q! zRQdo{F12^T5$7ldXvU%JnX+f^0Q;^IeweBYSEL&I#LpTQQ8Go0fM<_-*HI@m>Hvkf?@z{J(P649hTV98{6{0 zBxfh$03L!sWW-${frpS(sk(8VuvG?N@clD8o!*%7Bcjtpk@+6XTK8q)#Rbng)`TwPyNKV^$Srk*B70!OhnQlbU zb83qomwr3Q!9!81dba9&vjD4kBW6{;57!KY9RxT%;E8wdfMtK!vs86tT?nU-w3EII z5GhnsF+T@Ox5rfxpvqyz^675(yqmB3xAZnfiyFkM10wFaiZ8qW+9CyE;+mEDn|OB* zBnnkx(-Ef(t_Yqs1h`|*MF*6B0IkYhuxZ4Xo95TS{Dz>IpKObtn4Ru6e7X=rpjiG$I`*a_dKN)gP7iM3kv?_?+=jOR>~xSSPrfWhS~T$nuuGp8nOlLOaN@*d zNv-n<|M~~B-$E)T;} z@8=UaB-J6$7j}S?VS0}<1g7%_yNnk`d_jpcJs?b3+CdzTxeFuX|5o+1&+Xokb0nxNWSK;F@` z8&c-uXUzT?X+mX{Gp_Z)fkT}#<_vmer*&ntQWMGY@M28?dY&dBbD!y|JIX9{hU1NF zt=TH?%kqugfTXgVMD&IItdvvre*zu=mH@pSng9~vc=X%-`Z6dEo{^I^pk^FV$nT-9)Ek9X8X5V;2sZjmB1|YP42t|E63Ep=aX9H_TVo5wk>A zie81tH>V>v_hC~E!T!&O6nP%P>x9(tzJlWNm!Gr$?gi$6e5`>SKqX-?2Wf;sN=p&d zni1G02nG-`xT}Ub`!C+`o8sN?{*Z-IYDFP{wUYOmz{5berj}BSPq)OEmh{*Q zq_c9bgN@QbW|f&E1Tk?xTER5nKAgD^0!m0Mcg#A1*^iL6VqOAv&0A?3MDf;R);GG1 z!y!Pfr4pNwex<7?-n*EP5=u$7I`eMF@ELr+Sp?tkOf^Z3eM^b+y8^A_qlqZG%}#m> z)$MrL7HpV0Jw*Xgm7?mICxIXZEk<{9R5nmZg2Aw_XHm_n28R&V0Kx>A%+F$VT$aQE zu4UnQw&it`jGp2^1huT)vZU`Fz4uoD$xsY_6W3mOMu-_j7-5R29%BP1<0&zvKboe9 z))gKNc0n4g`6mdA3kl4Z2tN#$fWVI*7M#VcXK8_7b6zMnXp-(?IWk2x7P3Y}-)d%$UYszAN#+L<8btm`mitx!^M1gswv;B4XxD>IU`3@PM zj!~HyhB|S2{UA#hCZ)w3f98qOjMIJk#t=STDfb6`J-#YuFe@LCZ9}aymo|3!3h-GN zOG{`*@0MM5U;c5Yi=z^^Bq+JNL`c|_{3*MG1KVHxy8WQ2gMBtt3qWSYI|O8=(b!kq zR^8-#i|v-6P_RsAgZ2 z;+0!YXgY8A@~SVw`=Z0zZ`)cG;a7K@AIOb$N{{pk`N3~-wLqvaz}Z4Rv?o6DR$`F? zdSF(mdTkCiz+#y#xc2^~YN8A-fu$1>3kElWkuFeWa0JlF4tcQk$C(zw|8T$1p_-zH zjup^U*ddp!o*e@Qu2zHZMKHC;K%>SJbmBxKDcc}QL#)CwQiyPR-W%DY<8&8nzE1WH zSP}O$vOdpv0weEbu1I$s0_y^xj_!_B;kc)1)Lz%}fku$3@OyQ;>-?n)^}B2ZkHX(o zu%7Ab<4uhOgen985AH1a{qAHL`b`uvj)6L36_KC@RA6U3xhH7L+`AXafpnxkAOwTx zS|dci?@B8NUV*x&$p_oiKFCqkS_|_71{!s*Rn?S}oDFS`-=T#paj;7&FO7S!c2uI1 z6x#(6bnM`w{#J{3+|aBDHORVoFfpof2}rc90ps?&U1~Z_gKE$_+6E6hhkTBB6^fzrMn?j zO0cQStNK=UNUvhNIPlT*9@!lTPE-W&*6A@BT5`bMf> zXC60B8g&#GdW{EdH*Z)7#O=b$+=Ik55J>6yec$(N+jHEXb~cE$e41okH<3euH8&v6 zLd=cd9|B1G$koBX?XzwDuu<Xk5x^Az`IQdEI6_oBgIKdm~c0tqz$tu=AVH z6mX_V{5^uwlgbf)ry@Z5l~l4(&VZo($@h&)J8l5M;Sfjg+m;}QyDN(Ci>Cmw&2xw0@)gl8jxurMV5j(Q&@A+^UrVd~sqVsdJbuIh2U7{Vt*yq{5 zs-)NUgy_`E_YqzMnN?jchNuBTtP{Oq^Tw|y2KfCjR)=$P*D3#8Ldx`6+XnW_{%e10 z&6)vz0v9kn;rj<*uAuWfknE}9n&1h3QCW!>Iw0$?Aj-XZ`8c-#mqR4T5x;6AFKJZz zkQstt_}fS2ns~0BYR-Ae5i}Hd1~zSg5w7&@q=2c;gRRasGM{@A#>s-vnOOp0y{gA8 z?G%#9k#V_wzG1tynoF8HW8k%hrDbo`Mh)af=BW&&Buh=~!e;H+R=~TY0d~AhV_7pb zrzNKkq6x44dXC{6P}>Og`+$cs4im0@nsnXg)Yj;)28u|WzxBpRpk1US%-tfJL;&}s zHoru;7@z&{!g=akLEUE_7X&jtOBeQp{5GQM04w3F$cqbg;zqrX4bI2;oK{zOakjcg z4uO>y$ai}s4xLL}<%UTd`3Rd)qmS~Gbg;{~474!v3SyFj$&XO35k~rWp~AU4f-dXh zDIw$^4@7>)@)YGy(8(KPZXGxT@<0i>GBIE41(T<8qJWg&nrZ6SDr>li*P#-zM8`IA z^^xwJTWL$r`DRR9j2eFHyIp$-1ceqIN|DJyw)9Uu)mL-|k?L3v>tzA+nv6QB#f|cf zM`@4%=UT#QE?wwIr;exG%0}0jsHWSN00`3S6r3?6?MUujlTLMVINYVR>Afj7btk`L zHwDo|KnSWqPHz7SuXrxGz!_2QctAHM12Mua%l!BeV)8Vwi<(%H<*3G!6@Re;s5c_K z+)k#st895n>H~?HraaS23lqVG9*JdtAuK4xXGKuAv;-wRWATzN+54MIqeYdDh$f!8 z&*IzChJ*$YT`y~v8KS;50kTft&$A9p2N7+cFhLwI>T*Hty7LGX~oCSf4;0M|ljXwUN@wtcYF*@szcD~i0WR8HT z*iANk7$P2&{1Jc+xZ_KH1sjsTE6W4LyT<0q9+l>3co+kQCd|mQ_e)H8?7pU{_I^Hy zm%vuWuj-}?#I)ehN6nA(!kxJSy!#7;T#f?((W~ozyuG{kbFTLC5=Mivpq8Olv-i6t z{o^%j<&&Y3(}hGYR~_cK{ia1kjv7>g#iD;(ACHJ2-?yYiR`4(7T;KS_x~|%N4!i!Q zU*f=y9k{X9k8dhEh5cVD(B)yt*6|qVCzkqBDcq!dOJ$mOa7(M+H zRQoH%<>fVV_Lrl+^zu5nq!xw=E$G)FR2Mi~gCOkofvp4LrjS?A(mS!*?(s?&%#NqZ z6?2$1F1(EY1@L{5&1KE>tnT0KrHGIzaxrSaQ>6Fj9f_88EBG^Mg`JD7DS-1LQYm#J z=+gI6q1oB`RJ4~Oh*#u#q5Vj|eO-1F1W%q;h$OD-p7i#zOP8fq;uctG&X_} z0N5BfXW;ucfBYK>m}Iu#;6ghv1}0zy*{VpQ( z%hq; z|GfhK2IVFJ*d3sRh{GI+@Y+tc#E9dcHyRAN`D)^Ch06c^*81-YNB`B?`_Cu;$o=o% z{YMQ^)y+<#=EJdt>4L{&BT7ez(g-o*CYIjmO60Y6Nz;3Do@k{WKFp?@|?@(c+$?5iP!F2jK3yj8QB2eR_HyQiHtA!aBcs0UWF62I;Hn?}?ey z`vkj&W=->D-SlDczWV3cR*!$o^glJrx@QBubIEgx*If#}zLQwGx6B>ZljLfADN4{!P5@PpLxeJ-fS>y^vi&zuCQw(cwWhM{5?SYrZ2%uEcv zUUf&JgkGEQ;OBf4X{cM9P;r6=M=7u!tz<2w-Y7eR9C3Ajq@~pjd1hGKbDIE196=$A z;iuas?AG{;tx6$lw4qam{*gkM_alE^z2NUcL1fx=|F(?|n|;xRw1+y{kNS1JVYKYW zKklIUl-*jmx7<>WLLQ!ZvS@t3B!J9KD_Y8KSS1@|8oBGklD_`pA^W+6hc~f(FtYSB z`=rYv?SlGSQF;A_KHoxXwqO}wGF_`SvqWiffdw$Q28CLt4 z;dxQoZ;_Iv6T7jl-k)k!+@&@_BhI);Jyi6wrf@;!gy2mEV_EcVvtus^v?3;DPs5|e z1gu_c={Npj;a~E?n`fJSt`0R0WeYH+TuHLKrsmfIjC;AbB~MDxbdjdgmeV72<*5#m zSc)__v!#wc7CrI)IigZoT8yHE_xm$EQ)A+**0(e*C#h|&1pANLgs zvJzG~Qm|C41dBR*=UIOQ`Y4on2^lD=O#e^y*aS4lljccQ!dM9>zG&u7V)2rx3b9+i zH90ecv0Mp??i!T+NQ)aBp|O1#$WSQfxdZ=2EBjf0!Y`j$|DGwT(RFsr2D8^Vmf75U ziLJYaD-A0r51u2U3ZJN_WEUMKf0D;_HT#eNMxF*k^$Rumk&xs`>FYswE8tJ@4~<7) zcoo*xQkQYNNU`Yc>N*ot6|pNzSmje*^trJ~B}p103>y|`%QM*SLys3eL*&AI<+C*Ma(Q|Q`yeyh@sW~C zY#e&8x;&v`w$r3!=Hpnv85fEu6fXC`mS<^huHgY`I@rhFfpUax#GCT_wy;z||IauP zw)&PnE@|r612cX2c-lTa@e{>dSdihf>1baBOTfcC{}gq`fJ1 zV#I3tj|uDaNgF9*VR2Cdi^Wz^h$NEK&&sFjB2RCxc`nB5l|51$L1zB&2h@50gqG3E z_ZV*p>YJRam1<=Ct0)c&wY<@*a6`&&Hud8A1U0pIG^JRmgiz)?f8Ewrgl7EX;oXm) zrEUsLEu~MSn-23UGHBM{W$)pDJnSJutxP4Hj%=I4}8yA#^$LtfGFQ=Ofw$bh2ab9#pU=v$7>C2aMe4cFv_ZRyi0wDa;K)GKJZS^5$OU5yu3R2@1pzN+$WJlNL#-@-kDB+Lsw^%lFQEyQmOrSXls)Op=okRs@G zdJ-OwZOInou!|3F-cUjLUA~i?`JR|-?kM&20+*M`N5(Pj4fR6{ikR}r0Dj! zky>vSy+#ZSr5_a+dHL`BQzn*pPI@KCm){_S!O*E!{n0EUQTE8nVPpQiOQiNnS&9Fg zd(nT%aa=UCb2R_7Y(m+8TomikwQbOn>aX=`I>t@^&e!pHehp)9#OnHf=^B22m*bwu zcgA)+2~s#)wxIi|AWbL}FGdqr6sM`>2wjL%k)?-GYE-wRW~J?|o~4FF23-FnEqqp* z>a^Rk&%mRxp&UsgAy*&~`lb6UPtV@jwV@~RE2ghFytP7hlH-54 zx~6m?bz`~va!!t;>0`?b{TzNR{v1ytyZxgiMPE}+VM|Vp>F{2M?*+q|O2M`~iPf)i zoSt;Bj<=j)nTl{+yppeB5WDh3q+$8pp4S^|MCu*5QRCH1tt93%EVp#oK^iApYU{^4 zuh}z#uQR)fBQ{D5e__jWAlWG4LEZr69F6qN$S&}Lu{r1S6qe!1_4pRt*z{|XT_F3X z7B;?%P6kE|rSidhNO9jX5pO@u9MPug1t`g|pHQr+*khY)<-e z9LM!qmQ7xvvv7ILEHD6Vg)~@%WJRie(%3|U>c-$obOO64TD)EOkW-OLOCL5Ky`63P zEwuSPha|U&l%F-vJJKwtz9%Ke$$&MGpy6l{12-PI80)6Zc^4I&WLW>R#7wAQ^kELw zKNnT-e@H8X<;Zrc<}AX`5O)3tp3!avn4fK)Z~c-LWlct^yyDg!cN`fD+nr9Jl{z zS<*9LQEYx~WgBjXHz44T#BPkC&RxxNA9mmVD90wDp}5g??@-WnRfi+DCLURAOPU*3 zNqTLBxF6py+x^dbH?wsc@CfeF-P{zdc|RGmn*U^C&wm=39SY@4p`UG|E|*>93GB#s z&Abif`ug?F6Bf8jMtDZ|gHQ+eMz+AaJw@^@425B)_FYp*Ri3HsUb+`F;wM zp%!M8@I`fFnLfY^^*juf^#3$=8(fjwJ}`|-SV4&Y^Zk0iTW>SpUw-t8f9oprRG?e} znzPtuq5IkNwVB8X4d6F7bH+}gAUnpW$ z-k=p@`iiB3A)YW!#O|psPWbt5iFQ!I-A_IfkoKanN6NECskn!NPE*b`<@iOW#Pu7t zvg0|_v(N(HYaRG!`mg|7)1UDHBD7!FzSwvu!Vvs9TB0@OIR4l@9+dzQ6gJZo8$qbY zzpwl6qvU(zpaX6`kEgr-=Up$syB;W%E0DPEp-5x5{av`82Upk-t(b)NFrF;NZ@sN3 zpA`y2ENM{fyJS6V7jp(@*-o;2C|jCjPWg79vsfE7hGFB@wPbV_*8U#@nCF5Vhez2$ zU89?RU<)r#R8C_)#a=ZmF3L+S{;b%@KOLHQ=LC+(xkH6h8C*jeL{~u zZ^bIcad=nj-?yezcvY^&%~H0g?3%<}^cw$)PC`ue@7IyT(OZ?Rx^II=d(qFBBr9A% z>6MMOD!47qTr9PMay_Lysy%n{l{PwH@^a9$Y`j}#ha#3qJ-X;SX*Cw?fHCZ$y5sR= zBg!`Z8$GS-@s{ zQk}+p4am)1v^r!$0|T+EUs8x7>;* z>(W(O1KhdS9h1OVBK0-xDO{Tv(78tfk6;Qi*vf^4sGA; z?6)xH2O)Xb}yV|w7;gSH$;`nW~tDsizvO^H@ZIN^brNS zPs-9dc~KJv16Ph!f+(i@uWp>>K=v_@**i4-E1_OSoKgXNkn z=0j^M_@00O+nbse0gbVpCGI2%68gRHDfiJYr-;<9<3ii z#(h4a_T~gtVNZAam(d5NJKTOOJczN@)D@2vr~P6pioA8vh_RO7(kj)G*&9yE^*+u& zYwsVx@Rgz{*!P#XYli4?He2eUE%1xP^3`(I+%v7E-%_zI@UYqEI|@E?W0liH@exf~ zEwyJ1>eN(dKWv+zw=iuUw|5rw?nq3ok1BRZxJswJ;8PHQkxrtz$1Evxpy8cP7MDBV zvn^d~#x|+3dKDOwf#qfIRbi%mzt$U`t;>I6;mO@otosD~d(xzSgy+@4^MXg_R*(_lY;FWycFxf_DA=-eb>RHO9(f zz7YSt7owX^ZUnhs!j1fv$i>3yI!bmOK4qRApPrCxpI(UdoDreF&Z57f%=eCk*!66@ zAX}aw(vs@~^~K!RR?Wdd1^iR=XXpFDZ+G2ttru>S$QKtlNIP1da{HGPx|ex+ zUciFz{rXk4ux|w8`nA^U0#EMO>87J>WILr8!y@EIIf4m->Tfc4no@6ff3$QrZ23AlkxA{{l z$-DS8)MgD&6i{NHpilj`IJU&;%VN80^#!`9?kL}}$bCFr3L&s`_)j+{yX$Z4Ky0a} z*FyoG7OZbMu8g}{m;`i$n!X<#+!J_KnS!*#1YC{1}&Q%J_&2_*k@jUU*W0$p4(l{CfMg zW={XTqLQ{iKSBs4!1NJb>~Jv#-MHaI*#XAHm3!JiHGn%#BHZJ7arJZcBNF-bptj^f-bI+Bt`0hUp=S`-% zyXmt<+d3va;P$RC)ABZ+be+;wqkq`6*mnK14K@-9qOM=+RZ4a|i3K9pea=w0)Sr16 zU-B^a9*N)N^iq)-_n)HgVZ#N+e5$|JLb-t*$Ei;LSy1nR+=x&0$2+}y*bQM_(fPd1;5D2642D%g|KG>5*=~oiJsX@wdC;8%R?UHQFkAogDGwObXE}wXYGI+B zQ=V1*&(lJ|OE?sKZ!=U*{Yv%kWMo_Xey#7+4<0B;G?cTk&ApKbM#lLM?@CW7dh3G+ zNrs`2`%lXuhMH%v>?y=Z(oKjr`xMhyTfQ+n6UPy2=8}h} zmh`)0u(U<4I~QOW|1i*Om7!u*!MSSB;rntZeTiTV?w^l7E&<<1ib2aT?-uC=)jRXr|634Jy@SDzvXK7%ejV5W?|l#~v9sS>M)6Q} zH7e|XR8kz?{n^D>_sgGP?8&lydxt#W`6a2JbvO|7-G#T^hWI`%t0ss^F3NV?S2h2& zKRrz3SbML|zt3ZP@7e-(J6B(B@*FdJ6yEugp(&H&N9d_(7M^zLBJ4oHcP=Al=_^id ztP(P&e{|IsFpG|BJa<iX#{@wU~KxY zKf?Xn4n%LYeGHbN2aDqgcqZU`DxZT+I7Y@u{@i_E9EH2y(eI*gc}t`424ieU|J1yJ zJkCZJHqAkk={*h-cu0>!J=n(&o^_zi#2bxUD+)=Gz-&fRfXEeCfIRUjn5q+MYq^M1 z1n%kC;7gJZug~Zh7`-h{`+gtfeK^(~ZTi_)_njXi&%MMZa%XT*N^7J|=jX7pRe@n; z_qf0%n9lETC`e&A{ugx>GsQoiKgxP^z2onnUEclFmgg!@`~S82&)X-y`}Y~>i41XI z!if1I9ysU6J0xYmX^ezfOFwS(_#Pt<>Xa;JxNr!V3Ic&i52c$88d;d&d265MCFXcx zf94JCz@kQ^`@crlyPF6$QOS3Fsv#@Nx%s z+Lb`#6z=;ZK|KagPmlRP$qL=BM`!w73XioPg|`5Ffz9O%$IOb_CGmCVUtVTV4F$#O zlI}$-=1u~RF+hNWJFqm~vH=*gKib)qY(H=IkbYOjWa_Yc70|>dse!-&fr`tIK$)T& z<_7R6PcLwkNASG8-XgY)QroQ>VzDy7V%L4o%Qc{`aU86*dEp{3wsS$FC1p8%5;tXl z&CZVH|KG{aum1LYQC345uslvWcXIu|UDe-KFL#%>wO>@82kvOWs@Vf^Km*{wVP$9$ zKb!{~#!~|h)WHEI6V$LSKhUtz=_+`LGK>Z(tlR>YNEoXcMiUJ*rO;!_@z#I#s6U*% zN1jy#0&P_-ag8WRNi0dVN-jzTQVd20M#j2^hPsAkA%>P#CI(i9X4(b@Rt5%P`SqJo xH00)|WTsW()}U^598|_=z-=hW%uOvWNz5(4t*1c!*#%Hoc)I$ztaD0e0s!VQ@st1n diff --git a/src/Documentation/index.md b/src/Documentation/index.md index c2d95221..240a1725 100644 --- a/src/Documentation/index.md +++ b/src/Documentation/index.md @@ -1,17 +1,3 @@ -# Contents - -## [Python API Reference](~/api-python/index.md) - -Access the complete Python API Reference for comprehensive documentation. - -## [C# API Reference](~/api-csharp/index.md) - -Access the complete C# API Reference for detailed documentation. - -## [Code Samples](~/samples/intro.md) - -Explore code samples to kickstart your development process. - -## [Articles](~/articles/intro.md) - -Browse articles covering a range of topics, including customization of the Migration SDK. +--- +redirect_url: articles/index.html +--- diff --git a/src/Documentation/samples/batch-migration-completed/intro.md b/src/Documentation/samples/batch-migration-completed/intro.md deleted file mode 100644 index f22e29c3..00000000 --- a/src/Documentation/samples/batch-migration-completed/intro.md +++ /dev/null @@ -1,7 +0,0 @@ -# Batch Migration Completed - -Batch Migration Completed Hooks allow custom logic to run when a migration batch completes. - -The following samples cover some common scenarios: - -- [Sample: Migration batch logging](~/samples/batch-migration-completed/log_migration_batches.md) diff --git a/src/Documentation/samples/batch-migration-completed/log_migration_batches.md b/src/Documentation/samples/batch-migration-completed/log_migration_batches.md index fbd17eb3..2c27ca57 100644 --- a/src/Documentation/samples/batch-migration-completed/log_migration_batches.md +++ b/src/Documentation/samples/batch-migration-completed/log_migration_batches.md @@ -10,7 +10,7 @@ This example demonstrates how to log migration batch item statuses using a batch #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [//]: <> (Adding this as code as regions are not supported in Python snippets) ```Python @@ -26,7 +26,7 @@ plan_builder.hooks.add(LogMigrationBatchesHookForGroups) #### Registration -[Learn more.](~/samples/intro.md?tabs=CSharp#hook-registration) +[Learn more.](~/samples/index.md?tabs=CSharp#hook-registration) [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#LogMigrationBatchesHook-Registration)] diff --git a/src/Documentation/samples/bulk-post-publish/bulk_logging.md b/src/Documentation/samples/bulk-post-publish/bulk_logging.md index ff069dce..eab471f7 100644 --- a/src/Documentation/samples/bulk-post-publish/bulk_logging.md +++ b/src/Documentation/samples/bulk-post-publish/bulk_logging.md @@ -10,7 +10,7 @@ In the following example, a bulk post-publish hook logs published items. #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [//]: <> (Adding this as code as regions are not supported in python snippets) ```Python @@ -25,7 +25,7 @@ plan_builder.hooks.add(BulkLoggingHookForDataSources) #### Registration -[Learn more.](~/samples/intro.md?tabs=CSharp#hook-registration) +[Learn more.](~/samples/index.md?tabs=CSharp#hook-registration) [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#BulkLoggingHook-Registration)] diff --git a/src/Documentation/samples/bulk-post-publish/intro.md b/src/Documentation/samples/bulk-post-publish/intro.md deleted file mode 100644 index 1ba0bd3a..00000000 --- a/src/Documentation/samples/bulk-post-publish/intro.md +++ /dev/null @@ -1,7 +0,0 @@ -# Bulk Post-Publish Hooks - -Bulk post-publish hooks allow you to update content item batches after they are migrated to the destination. - -The following samples cover some common scenarios: - -- [Sample: Bulk logging](~/samples/bulk-post-publish/bulk_logging.md) diff --git a/src/Documentation/samples/filters/filter_projects_by_name.md b/src/Documentation/samples/filters/filter_projects_by_name.md index df82dd00..dfffc55c 100644 --- a/src/Documentation/samples/filters/filter_projects_by_name.md +++ b/src/Documentation/samples/filters/filter_projects_by_name.md @@ -10,7 +10,7 @@ In this example, the project named `Default` is filtered out. #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [//]: <> (Adding this as code as regions are not supported in Python snippets) ```Python @@ -25,7 +25,7 @@ plan_builder.filters.add(DefaultProjectFilter) #### Registration -[Learn more.](~/samples/intro.md?tabs=CSharp#hook-registration) +[Learn more.](~/samples/index.md?tabs=CSharp#hook-registration) [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#DefaultProjectsFilter-Registration)] diff --git a/src/Documentation/samples/filters/filter_users_by_site_role.md b/src/Documentation/samples/filters/filter_users_by_site_role.md index 227b9f0c..12f2e795 100644 --- a/src/Documentation/samples/filters/filter_users_by_site_role.md +++ b/src/Documentation/samples/filters/filter_users_by_site_role.md @@ -10,7 +10,7 @@ In this example, all unlicensed users are excluded from migration. #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [//]: <> (Adding this as code as regions are not supported in Python snippets) ```Python @@ -25,7 +25,7 @@ plan_builder.filters.add(UnlicensedUserFilter) #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#UnlicensedUsersFilter-Registration)] diff --git a/src/Documentation/samples/filters/intro.md b/src/Documentation/samples/filters/intro.md deleted file mode 100644 index d8e7b6de..00000000 --- a/src/Documentation/samples/filters/intro.md +++ /dev/null @@ -1,12 +0,0 @@ -# Filters - -Filters allow you to skip migrating certain content items. - -> [!Note] -> Filters do not have a cascading effect. You will need to write similar filters for the related content items as well. - -The following samples cover some common scenarios: - -- [Sample: Filter projects by name](~/samples/filters/filter_projects_by_name.md) - -- [Sample: Filter users by site role](~/samples/filters/filter_users_by_site_role.md) diff --git a/src/Documentation/samples/intro.md b/src/Documentation/samples/intro.md deleted file mode 100644 index 5de560fa..00000000 --- a/src/Documentation/samples/intro.md +++ /dev/null @@ -1,48 +0,0 @@ -# Code Samples - -Once you have started building your migration using the example code in [C#](~/api-csharp/index.md) or [Python](~/api-python/index.md), you may want to further customize your migration using hooks. This section provides code samples to assist you. - -[Learn more about hooks here.](~/articles/hooks/index.md) - -## Hook Registration - -To use hooks, you need to register them with the [plan builder](~/articles/configuration.md#migration-plan). - -The process of registering hooks differs slightly between C# and Python, as described below. - -# [Python](#tab/Python) - -In Python, injecting an object into the class constructor is not supported, and in most cases, it is unnecessary. - -To register a Python hook object, simply create the object and add it to the appropriate hook type collection. - -**Generic Form:** `plan_builder.[hook type collection].add([hook object])` - -**Example:** -``` -plan_builder.filters.add(UnlicensedUsersFilter) -``` - -# [C#](#tab/CSharp) - -In C#, the hook object should be registered with Dependency Injection (DI). This allows hooks to have any object injected into the constructor without concern for the source of the object. - -Learn more about [dependency injection](~/articles/dependency_injection.md). - -To register your hook object with the dependency injection service provider, simply add it. - -**Generic Form:** `services.AddScoped<[Object type]>();` - -**Example:** -``` -services.AddScoped(); -``` - -Once the hook is registered with DI, it must be added to the appropriate [hook collection](~/articles/hooks/custom_hooks.md). - -**Generic Form:** `_planBuilder.[hook type collection].Add<[object name], [hook type]>();` - -**Example:** -``` -_planBuilder.Filters.Add(); -``` diff --git a/src/Documentation/samples/mappings/change_projects.md b/src/Documentation/samples/mappings/change_projects.md index de61d747..bfaa1b09 100644 --- a/src/Documentation/samples/mappings/change_projects.md +++ b/src/Documentation/samples/mappings/change_projects.md @@ -12,7 +12,7 @@ Both the C# and Python mapping classes inherit from a base class that handles mo #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [//]: <> (Adding this as code as regions are not supported in Python snippets) ```Python @@ -28,7 +28,7 @@ plan_builder.mappings.add(ChangeProjectMappingForDataSources) #### Registration -[Learn more.](~/samples/intro.md?tabs=CSharp#hook-registration) +[Learn more.](~/samples/index.md?tabs=CSharp#hook-registration) [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#ChangeProjectMapping-Registration)] diff --git a/src/Documentation/samples/mappings/intro.md b/src/Documentation/samples/mappings/intro.md deleted file mode 100644 index 4a1d8694..00000000 --- a/src/Documentation/samples/mappings/intro.md +++ /dev/null @@ -1,12 +0,0 @@ -# Mappings - -Mappings allow you to change the locations of content items before they are migrated to the destination. - -> [!Note] -> Mappings do not have a cascading effect. You will need to write similar mappings for the related content items as well. - -The following samples cover some common scenarios: - -- [Sample: Username email](~/samples/mappings/username_email_mapping.md) -- [Sample: Rename projects](~/samples/mappings/rename_projects.md) -- [Sample: Change projects](~/samples/mappings/change_projects.md) diff --git a/src/Documentation/samples/mappings/rename_projects.md b/src/Documentation/samples/mappings/rename_projects.md index 666c335e..fdb178af 100644 --- a/src/Documentation/samples/mappings/rename_projects.md +++ b/src/Documentation/samples/mappings/rename_projects.md @@ -10,7 +10,7 @@ In this example, the source project named `Test` is renamed to `Production` on t #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) [//]: <> (Adding this as code as regions are not supported in Python snippets) ```Python @@ -25,7 +25,7 @@ plan_builder.mappings.add(EmailDomainMapping) #### Registration -[Learn more.](~/samples/intro.md?tabs=CSharp#hook-registration) +[Learn more.](~/samples/index.md?tabs=CSharp#hook-registration) [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#ProjectRenameMapping-Registration)] diff --git a/src/Documentation/samples/mappings/username_email_mapping.md b/src/Documentation/samples/mappings/username_email_mapping.md index 7801148f..3abef020 100644 --- a/src/Documentation/samples/mappings/username_email_mapping.md +++ b/src/Documentation/samples/mappings/username_email_mapping.md @@ -10,7 +10,7 @@ This example is for a hypothetical scenario where the Tableau Server usernames a #### Registration -[Learn more.](~/samples/intro.md?tabs=Python#hook-registration) +[Learn more.](~/samples/index.md?tabs=Python#hook-registration) See the line with `with_tableau_cloud_usernames`. @@ -39,22 +39,22 @@ This uses a configuration class to supply the email domain. #### Mapping Class -[!code-csharp[CS](../../../../examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMapping.cs#namespace)] +[!code-csharp[](../../../../examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMapping.cs#namespace)] #### Configuration Class -[!code-csharp[CS](../../../../examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMappingOptions.cs)] +[!code-csharp[](../../../../examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMappingOptions.cs)] #### Registration -[Learn more.](~/samples/intro.md?tabs=CSharp#hook-registration) +[Learn more.](~/samples/index.md?tabs=CSharp#hook-registration) See the line with `WithTableauCloudUsernames`. -[!code-csharp[CS](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#EmailDomainMapping-Registration)] +[!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#EmailDomainMapping-Registration)] #### Dependency Injection [Learn more.](~/articles/dependency_injection.md) -[!code-csharp[CS](../../../../examples/Csharp.ExampleApplication/Program.cs#EmailDomainMapping-DI)] +[!code-csharp[](../../../../examples/Csharp.ExampleApplication/Program.cs#EmailDomainMapping-DI)] diff --git a/src/Documentation/samples/migration-action-completed/intro.md b/src/Documentation/samples/migration-action-completed/intro.md deleted file mode 100644 index 0934c331..00000000 --- a/src/Documentation/samples/migration-action-completed/intro.md +++ /dev/null @@ -1,7 +0,0 @@ -# Migration Action Completed - -Migration Action Completed Hooks allow custom logic to run when a migration action completes. - -The following samples cover some common scenarios: - -- [Sample: Migration action logging](~/samples/migration-action-completed/log_migration_actions.md) diff --git a/src/Documentation/samples/migration-action-completed/log_migration_actions.md b/src/Documentation/samples/migration-action-completed/log_migration_actions.md index 475f9ba6..de30f6e6 100644 --- a/src/Documentation/samples/migration-action-completed/log_migration_actions.md +++ b/src/Documentation/samples/migration-action-completed/log_migration_actions.md @@ -12,7 +12,7 @@ To log migration action statuses in Python, you can utilize the following hook c ### Registration -For guidance on registering the hook, refer to the [documentation](~/samples/intro.md?tabs=Python#hook-registration). +For guidance on registering the hook, refer to the [documentation](~/samples/index.md?tabs=Python#hook-registration). [//]: <> (Adding this as code as regions are not supported in python snippets) ```Python @@ -30,7 +30,7 @@ In C#, you can implement the migration action completed hook as demonstrated bel ### Registration -To register the hook in C#, follow the instructions provided in the [documentation](~/samples/intro.md?tabs=CSharp#hook-registration). +To register the hook in C#, follow the instructions provided in the [documentation](~/samples/index.md?tabs=CSharp#hook-registration). [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#LogMigrationActionsHook-Registration)] diff --git a/src/Documentation/samples/post-publish/intro.md b/src/Documentation/samples/post-publish/intro.md deleted file mode 100644 index 7da70bc5..00000000 --- a/src/Documentation/samples/post-publish/intro.md +++ /dev/null @@ -1,7 +0,0 @@ -# Post-Publish Hooks - -Post-publish hooks allow you to update content items after they are migrated to the destination. - -The following samples cover some common scenarios: - -- [Sample: Update permissions](~/samples/post-publish/update_permissions.md) diff --git a/src/Documentation/samples/toc.yml b/src/Documentation/samples/toc.yml index 16a0b3d9..82bca686 100644 --- a/src/Documentation/samples/toc.yml +++ b/src/Documentation/samples/toc.yml @@ -1,23 +1,21 @@ -- name: Introduction - href: intro.md - name: Filters href: filters/toc.yml - homepage: filters/intro.md + homepage: filters/index.md - name: Mappings href: mappings/toc.yml - homepage: mappings/intro.md + homepage: mappings/index.md - name: Transformers href: transformers/toc.yml - homepage: transformers/intro.md + homepage: transformers/index.md - name: Post-Publish Hooks href: post-publish/toc.yml - homepage: post-publish/intro.md + homepage: post-publish/index.md - name: Bulk Post-Publish Hooks href: bulk-post-publish/toc.yml - homepage: bulk-post-publish/intro.md + homepage: bulk-post-publish/index.md - name: Batch Migration Completed Hooks href: batch-migration-completed/toc.yml - homepage: batch-migration-completed/intro.md + homepage: batch-migration-completed/index.md - name: Migration Action Completed Hooks href: migration-action-completed/toc.yml - homepage: migration-action-completed/intro.md + homepage: migration-action-completed/index.md diff --git a/src/Documentation/samples/transformers/encrypt_extracts_transformer.md b/src/Documentation/samples/transformers/encrypt_extracts_transformer.md index 4e35d802..dc0f6ac4 100644 --- a/src/Documentation/samples/transformers/encrypt_extracts_transformer.md +++ b/src/Documentation/samples/transformers/encrypt_extracts_transformer.md @@ -14,7 +14,7 @@ To encrypt extracts in Python, you can use the following transformer class: ### Registration -Refer to the [documentation](~/samples/intro.md?tabs=Python#hook-registration) for instructions on registering the transformer. +Refer to the [documentation](~/samples/index.md?tabs=Python#hook-registration) for instructions on registering the transformer. [//]: <> (Adding this as code as regions are not supported in python snippets) ```Python @@ -32,7 +32,7 @@ In C#, the transformer class for encrypting extracts is implemented as follows: ### Registration -To register the transformer in C#, follow the guidance provided in the [documentation](~/samples/intro.md?tabs=CSharp#hook-registration). +To register the transformer in C#, follow the guidance provided in the [documentation](~/samples/index.md?tabs=CSharp#hook-registration). [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#EncryptExtractTransformer-Registration)] diff --git a/src/Documentation/samples/transformers/intro.md b/src/Documentation/samples/transformers/intro.md deleted file mode 100644 index 3712c7e5..00000000 --- a/src/Documentation/samples/transformers/intro.md +++ /dev/null @@ -1,8 +0,0 @@ -# Transformers - -Transformers allow you to update content items before they are migrated to the destination. - -The following samples cover some common scenarios: - -- [Sample: Add tags to content](~/samples/transformers/migrated_tag_transformer.md) -- [Sample: Encrypt Extracts](~/samples/transformers/encrypt_extracts_transformer.md) \ No newline at end of file diff --git a/src/Documentation/samples/transformers/migrated_tag_transformer.md b/src/Documentation/samples/transformers/migrated_tag_transformer.md index 54af8cff..59502a5c 100644 --- a/src/Documentation/samples/transformers/migrated_tag_transformer.md +++ b/src/Documentation/samples/transformers/migrated_tag_transformer.md @@ -14,7 +14,7 @@ To implement the tag addition in Python, you can utilize the following transform ### Registration -For detailed instructions on registering the transformer, refer to the [documentation](~/samples/intro.md?tabs=Python#hook-registration). +For detailed instructions on registering the transformer, refer to the [documentation](~/samples/index.md?tabs=Python#hook-registration). [//]: <> (Adding this as code as regions are not supported in python snippets) ```Python @@ -32,7 +32,7 @@ In C#, the transformer class for adding tags is implemented as shown below: ### Registration -To register the transformer in C#, follow the guidance provided in the [documentation](~/samples/intro.md?tabs=CSharp#hook-registration). +To register the transformer in C#, follow the guidance provided in the [documentation](~/samples/index.md?tabs=CSharp#hook-registration). [!code-csharp[](../../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#MigratedTagTransformer-Registration)] diff --git a/src/Documentation/samples/transformers/toc.yml b/src/Documentation/samples/transformers/toc.yml index 2011f4a7..aa9cdcca 100644 --- a/src/Documentation/samples/transformers/toc.yml +++ b/src/Documentation/samples/transformers/toc.yml @@ -2,3 +2,5 @@ href: migrated_tag_transformer.md - name: Encrypt Extracts href: encrypt_extracts_transformer.md +- name: Adjust 'Start At' to Scheduled Tasks + href: start_at_transformer.md diff --git a/src/Documentation/templates/tableau/styles/main.css b/src/Documentation/templates/tableau/styles/main.css index 6de48a3d..dea25a1e 100644 --- a/src/Documentation/templates/tableau/styles/main.css +++ b/src/Documentation/templates/tableau/styles/main.css @@ -3,11 +3,12 @@ body { font-family: "Open Sans", Helvetica, Arial, sans-serif; color: #555; + line-height: 2em; } .toc .nav>li>a { color: #337ab7; - margin-left: 5px; + padding: 10px 15px; display: block; padding: 0; } @@ -140,6 +141,10 @@ body .toc { color: #337ab7 } +.tableau-navbar-title>a:hover { + text-decoration: none; +} + .tableau-navbar-version { font-size: 15px; color: #337ab7 @@ -156,26 +161,165 @@ body .toc { max-height: 100%; } +/* Top menu styles*/ + +.navbar-inverse .navbar-nav>.active>a { + background-color: transparent; + font-weight: bold; + color: #337ab7; +} + /* Alerts */ + .alert { - padding: 12px; - border-radius: 8px; - border-width: 0px; - box-shadow: 0px 2px 2px 0px #c7c7c766; + padding: 15px; + border-radius: 4px; +} + +.alert-info { + background-color: #e8f6fd; +} + +.alert-danger, +.alert-warning, +.alert-info { + color: #555; +} + +.alert-warning { + background-color: #f7e7bd; +} + +.alert-danger { + background-color: #ffebee; } /* Code blocks*/ pre { - border-radius: 10px; - box-shadow: 0px 2px 2px 0px #c7c7c766; + border-radius: 4px; + margin-left: 10px 0px; + border: 1px solid #f3f3f3; } +.tabGroup section[role="tabpanel"] { + border: 2px solid #f7f7f7; + padding: 22px; +} .tabGroup a[role="tab"]:hover, .tabGroup a[role="tab"]:focus, .tabGroup a[role="tab"][aria-selected="true"] { - font-weight: bold; - /* Make the selected tab heading bold # Brings the tab color scheme in line with the rest of the site */ - border-bottom: 2px solid #337ab7; - color: #337ab7; + border-bottom: 2px solid #337ab7; + color: #337ab7; + font-weight: bold; +} + +.tabGroup a[role="tab"]:focus { + outline: none; +} + +/* Text */ + +h1, +.h1 { + font-size: 32px +} + +h2, +.h2 { + font-size: 26px +} + +h3, +.h3 { + font-size: 20px +} + +h4, +.h4 { + font-size: 16px +} + +h5, +.h5 { + font-size: 14px +} + +h6, +.h6 { + font-size: 12px +} + +article h1 { + margin-top: 0px; +} + +/* Tables */ + +table { + border: 1px solid #c2c2c2; + border-collapse: collapse; + margin: 1em 0px; +} + +th { + font-weight: bold; + border: 1px solid #c2c2c2; + text-align: left; + padding: 0.3em; + vertical-align: top; + background-color: #fafafa; +} + +td { + border: 1px solid #c2c2c2; + text-align: left; + padding: 0.3em; + vertical-align: top; } + +.table-bordered { + border: 1px solid #c2c2c2; +} + +.table-bordered>thead>tr>th, +.table-bordered>thead>tr>td { + border-bottom-width: 1px; +} + +.table-bordered>thead>tr>th, +.table-bordered>tbody>tr>th, +.table-bordered>tfoot>tr>th, +.table-bordered>thead>tr>td, +.table-bordered>tbody>tr>td, +.table-bordered>tfoot>tr>td { + border: 1px solid #c2c2c2; +} + +.table-condensed>thead>tr>th, +.table-condensed>tbody>tr>th, +.table-condensed>tfoot>tr>th, +.table-condensed>thead>tr>td, +.table-condensed>tbody>tr>td, +.table-condensed>tfoot>tr>td { + padding: 0.3em; +} + +/* Links */ + +a { + color: #337ab7; + text-decoration: none; + background-color: transparent; +} + +a:focus, +a:hover { + color: #23527c; + text-decoration: underline; +} + +a:active, +a:hover { + outline: 0; +} \ No newline at end of file diff --git a/src/Documentation/toc.yml b/src/Documentation/toc.yml index 29ce2204..33aa4c8a 100644 --- a/src/Documentation/toc.yml +++ b/src/Documentation/toc.yml @@ -1,12 +1,12 @@ +- name: Articles + href: articles/ + homepage: articles/index.md +- name: Code Samples + href: samples/ + homepage: samples/index.md - name: Python API Reference href: api-python/ homepage: api-python/index.md - name: C# API Reference href: api-csharp/ - homepage: api-csharp/index.md -- name: Code Samples - href: samples/ - homepage: samples/intro.md -- name: Articles - href: articles/ - homepage: articles/intro.md \ No newline at end of file + homepage: api-csharp/index.md diff --git a/src/Python/CONTRIBUTING.md b/src/Python/CONTRIBUTING.md index ea48d905..743f68bc 100644 --- a/src/Python/CONTRIBUTING.md +++ b/src/Python/CONTRIBUTING.md @@ -10,9 +10,9 @@ Python port for the Tableau Migration SDK * _Optional_: Update PIP and SetupTools to the latest version by executing `python -m pip install --upgrade pip setuptools` * PIP and SetupTools are the only pre-loaded modules on a clean Windows installation * _Optional_ for hatch: Install pytest globally to run tests on Visual Studio - * `python -m pip install pytest` + * `python -m pip install --upgrade pytest pytest-env` * Install hatch globally - * `python -m pip install hatch` + * `python -m pip install --upgrade hatch` * Create the Python virtual environment * (From migration-sdk/src/Python): `python -m venv env --system-site-packages --upgrade-deps` * _Optional_ for hatch: Activate the virtual environment to run tests on Visual Studio @@ -41,7 +41,7 @@ To run ruff locally: * Activate the virtual environment: * `.\env\Scripts\Activate.ps1`. * Execute linter: - * `python -m ruff --format=github .`. + * `python -m ruff check --output-format=github .`. * **With hatch**: * Execute linter: * `python -m hatch run lint:lint`. @@ -58,7 +58,7 @@ To generate the documentation locally: * Activate the virtual environment: * `.\env\Scripts\Activate.ps1`. * Generate documentation: - * `python -m sphinx -M markdown .\Documentation\ ..\Documentation\python\`. + * `python -m sphinx -M markdown .\Documentation\ ..\Documentation\python\ -Q`. * **With hatch**: * Generate documentation: * `python -m hatch run docs:docs`. @@ -103,9 +103,9 @@ Python tests also run in the CI/CD pipeline on all supported OS types. ## Building and publishing -Overriding an existing package version is not supported in `artifactory`. +Overriding an existing package version is not supported. -This script will build the package and upload it to `artifactory`. `scripts/publish-package.ps1`. +This script will build the package and upload it to package repository. `scripts/publish-package.ps1`. Use the flag **$SkipPublish** to disable the `python -m twine upload` if you don't want to upload. diff --git a/src/Python/Python.pyproj b/src/Python/Python.pyproj index 8ebcb3dd..63c22230 100644 --- a/src/Python/Python.pyproj +++ b/src/Python/Python.pyproj @@ -30,6 +30,7 @@ + @@ -56,12 +57,16 @@ + + + + @@ -75,6 +80,7 @@ + @@ -89,6 +95,10 @@ + + + + diff --git a/src/Python/pyproject.toml b/src/Python/pyproject.toml index 9b034790..059191e0 100644 --- a/src/Python/pyproject.toml +++ b/src/Python/pyproject.toml @@ -20,10 +20,9 @@ classifiers = [ license = "Apache-2.0" dependencies = [ - "typing_extensions==4.9.0", + "typing_extensions==4.12.2", "cffi==1.16.0", - "clr-loader==0.2.6", - "pycparser==2.21", + "pycparser==2.22", "pythonnet==3.0.3" ] @@ -40,23 +39,23 @@ dependencies = [ ] [tool.hatch.envs.docs.scripts] -docs = "sphinx-build -M markdown .\\Documentation\\ ..\\Documentation\\python\\" +docs = "sphinx-build -M markdown .\\Documentation\\ ..\\Documentation\\python\\ -Q" [tool.hatch.envs.lint] detached = true dependencies = [ - "ruff==0.2.2" + "ruff==0.5.0" ] [tool.hatch.envs.lint.scripts] -lint = "ruff ." +lint = "ruff check ." [tool.hatch.envs.test] dev-mode = false dependencies = [ - "pytest>=8.0.1", - "pytest-cov>=4.1.0", + "pytest>=8.2.2", + "pytest-cov>=5.0.0", "pytest-env>=1.1.3" ] diff --git a/src/Python/requirements.txt b/src/Python/requirements.txt index 58d776af..95014b79 100644 --- a/src/Python/requirements.txt +++ b/src/Python/requirements.txt @@ -1,4 +1,4 @@ cffi==1.16.0 -pycparser==2.21 +pycparser==2.22 pythonnet==3.0.3 -typing_extensions==4.9.0 +typing_extensions==4.12.2 diff --git a/src/Python/scripts/build_binaries.py b/src/Python/scripts/build_binaries.py index 607dd382..9dd0003b 100644 --- a/src/Python/scripts/build_binaries.py +++ b/src/Python/scripts/build_binaries.py @@ -14,9 +14,4 @@ sys.path.append(bin_path) shutil.rmtree(bin_path, True) -subprocess.run(["dotnet", "publish", migration_project, "-o", bin_path, "-f", "net6.0"]) - -# Regenerate automated Python wrapper tool. -gen_path = bin_path + "/generator" -generator_project = abspath("../../Tableau.Migration.PythonGenerator/Tableau.Migration.PythonGenerator.csproj") -subprocess.run(["dotnet", "public", generator_project, "-o", gen_path]) +subprocess.run(["dotnet", "publish", migration_project, "-o", bin_path, "-f", "net6.0"]) \ No newline at end of file diff --git a/src/Python/scripts/publish-package.ps1 b/src/Python/scripts/publish-package.ps1 index c0ace314..54e63622 100644 --- a/src/Python/scripts/publish-package.ps1 +++ b/src/Python/scripts/publish-package.ps1 @@ -40,9 +40,6 @@ function Test-CommandExists ($command) pushd (Join-Path $PSScriptRoot "..") -$env:TWINE_REPOSITORY="tabpypi" -$env:TWINE_REPOSITORY_URL="https://artifactory.prod.tableautools.com/artifactory/api/pypi/tabpypi" -$env:TWINE_USERNAME="svc_cmt" $env:TWINE_NON_INTERACTIVE="1" if (-not($SkipPublish)) { @@ -69,9 +66,9 @@ try { python -m build --sdist # Build the source dist package if (-not($SkipPublish)) { - # The package will be uploaded to https://artifactory.prod.tableautools.com/ui/repos/tree/General/tabpypi/tableau-migration/ - Write-Host "Uploading package to https://artifactory.prod.tableautools.com/ui/repos/tree/General/tabpypi/tableau-migration/" - python -m twine upload --repository-url https://artifactory.prod.tableautools.com/artifactory/api/pypi/tabpypi dist/* + # The package will be uploaded to the package repository + Write-Host "Uploading package to $($env:TWINE_REPOSITORY_URL)" + python -m twine upload --repository-url $env:TWINE_REPOSITORY_URL dist/* } } diff --git a/src/Python/src/tableau_migration/__init__.py b/src/Python/src/tableau_migration/__init__.py index ff94a11a..806aab34 100644 --- a/src/Python/src/tableau_migration/__init__.py +++ b/src/Python/src/tableau_migration/__init__.py @@ -73,6 +73,8 @@ from tableau_migration.migration_engine_endpoints_search import PyDestinationContentReferenceFinderFactory as IDestinationContentReferenceFinderFactory # noqa: E402, F401 from tableau_migration.migration_engine_endpoints_search import PySourceContentReferenceFinder as ISourceContentReferenceFinder # noqa: E402, F401 from tableau_migration.migration_engine_endpoints_search import PySourceContentReferenceFinderFactory as ISourceContentReferenceFinderFactory # noqa: E402, F401 +from tableau_migration.migration_content_schedules_cloud import PyCloudExtractRefreshTask as ICloudExtractRefreshTask # noqa: E402, F401 +from tableau_migration.migration_content_schedules_server import PyServerExtractRefreshTask as IServerExtractRefreshTask # noqa: E402, F401 # region _generated @@ -80,6 +82,7 @@ from tableau_migration.migration import PyContentReference as IContentReference # noqa: E402, F401 from tableau_migration.migration import PyMigrationCompletionStatus as MigrationCompletionStatus # noqa: E402, F401 from tableau_migration.migration import PyResult as IResult # noqa: E402, F401 +from tableau_migration.migration_api_rest import PyRestIdentifiable as IRestIdentifiable # noqa: E402, F401 from tableau_migration.migration_api_rest_models import PyAdministratorLevels as AdministratorLevels # noqa: E402, F401 from tableau_migration.migration_api_rest_models import PyContentPermissions as ContentPermissions # noqa: E402, F401 from tableau_migration.migration_api_rest_models import PyExtractEncryptionModes as ExtractEncryptionModes # noqa: E402, F401 @@ -119,6 +122,14 @@ from tableau_migration.migration_content_permissions import PyGranteeCapability as IGranteeCapability # noqa: E402, F401 from tableau_migration.migration_content_permissions import PyGranteeType as GranteeType # noqa: E402, F401 from tableau_migration.migration_content_permissions import PyPermissions as IPermissions # noqa: E402, F401 +from tableau_migration.migration_content_schedules import PyExtractRefreshContentType as ExtractRefreshContentType # noqa: E402, F401 +from tableau_migration.migration_content_schedules import PyExtractRefreshTask as IExtractRefreshTask # noqa: E402, F401 +from tableau_migration.migration_content_schedules import PyFrequencyDetails as IFrequencyDetails # noqa: E402, F401 +from tableau_migration.migration_content_schedules import PyInterval as IInterval # noqa: E402, F401 +from tableau_migration.migration_content_schedules import PySchedule as ISchedule # noqa: E402, F401 +from tableau_migration.migration_content_schedules import PyWithSchedule as IWithSchedule # noqa: E402, F401 +from tableau_migration.migration_content_schedules_cloud import PyCloudSchedule as ICloudSchedule # noqa: E402, F401 +from tableau_migration.migration_content_schedules_server import PyServerSchedule as IServerSchedule # noqa: E402, F401 from tableau_migration.migration_engine import PyContentMigrationItem as ContentMigrationItem # noqa: E402, F401 from tableau_migration.migration_engine_actions import PyMigrationActionResult as IMigrationActionResult # noqa: E402, F401 from tableau_migration.migration_engine_hooks_mappings import PyContentMappingContext as ContentMappingContext # noqa: E402, F401 diff --git a/src/Python/src/tableau_migration/migration.py b/src/Python/src/tableau_migration/migration.py index 9761c6be..70c09359 100644 --- a/src/Python/src/tableau_migration/migration.py +++ b/src/Python/src/tableau_migration/migration.py @@ -209,13 +209,12 @@ def add_errors(self, errors) -> Self: # region _generated from enum import IntEnum # noqa: E402, F401 +from tableau_migration.migration_api_rest import PyRestIdentifiable # noqa: E402, F401 from typing import Sequence # noqa: E402, F401 from typing_extensions import Self # noqa: E402, F401 -from uuid import UUID # noqa: E402, F401 import System # noqa: E402 -from System import Guid # noqa: E402, F401 from Tableau.Migration import ( # noqa: E402, F401 ContentLocation, IContentReference, @@ -318,7 +317,7 @@ def parent(self) -> Self: result = self._dotnet.Parent() return None if result is None else PyContentLocation(result) -class PyContentReference(): +class PyContentReference(PyRestIdentifiable): """Interface for an object that describes information on how to reference an item of content, for example through a Tableau API.""" _dotnet_base = IContentReference @@ -333,11 +332,6 @@ def __init__(self, content_reference: IContentReference) -> None: """ self._dotnet = content_reference - @property - def id(self) -> UUID: - """Gets the unique identifier of the content item, corresponding to the LUID in the Tableau REST API.""" - return None if self._dotnet.Id is None else UUID(self._dotnet.Id.ToString()) - @property def content_url(self) -> str: """Get the site-unique "content URL" of the content item, or an empty string if the content type does not use a content URL.""" diff --git a/src/Python/src/tableau_migration/migration_content.py b/src/Python/src/tableau_migration/migration_content.py index f321f9b1..cf562af2 100644 --- a/src/Python/src/tableau_migration/migration_content.py +++ b/src/Python/src/tableau_migration/migration_content.py @@ -18,6 +18,7 @@ # region _generated from tableau_migration.migration import PyContentReference # noqa: E402, F401 +from tableau_migration.migration_api_rest import PyRestIdentifiable # noqa: E402, F401 from typing import ( # noqa: E402, F401 Sequence, List @@ -455,7 +456,7 @@ def user(self, value: PyContentReference) -> None: """Gets the user that belongs to a group.""" self._dotnet.User = None if value is None else value._dotnet -class PyLabel(): +class PyLabel(PyRestIdentifiable): """Interface for a content item's label.""" _dotnet_base = ILabel diff --git a/src/Python/src/tableau_migration/migration_engine_endpoints_search.py b/src/Python/src/tableau_migration/migration_engine_endpoints_search.py index b8d50605..3e49adf7 100644 --- a/src/Python/src/tableau_migration/migration_engine_endpoints_search.py +++ b/src/Python/src/tableau_migration/migration_engine_endpoints_search.py @@ -56,7 +56,7 @@ def __init__(self, destination_content_reference_finder: IDestinationContentRefe """Creates a new PyDestinationContentReferenceFinder object. Args: - destination_content_reference_finder: A ISyncDestinationContentReferenceFinder object. + destination_content_reference_finder: A IDestinationContentReferenceFinder object. t: The content type. Returns: None. @@ -163,7 +163,7 @@ def __init__(self, source_content_reference_finder: ISourceContentReferenceFinde """Creates a new PySourceContentReferenceFinder object. Args: - source_content_reference_finder: A ISyncSourceContentReferenceFinder object. + source_content_reference_finder: A ISourceContentReferenceFinder object. t: The content type. Returns: None. diff --git a/src/Python/src/tableau_migration/migration_engine_migrators.py b/src/Python/src/tableau_migration/migration_engine_migrators.py index 951a51ea..f2e589ce 100644 --- a/src/Python/src/tableau_migration/migration_engine_migrators.py +++ b/src/Python/src/tableau_migration/migration_engine_migrators.py @@ -45,7 +45,7 @@ def execute(self, plan: PyMigrationPlan, previous_manifest: PyMigrationManifest Args: plan: The migration plan to execute. previous_manifest: A manifest from a previous migration of the same plan to use to determine what progress has already been made. - cancel: A cancellation token to obey. + cancel: The cancellation token to obey. Returns: The results of the migration. """ diff --git a/src/Python/tests/test_classes.py b/src/Python/tests/test_classes.py index e50db6c4..d84d8bb6 100644 --- a/src/Python/tests/test_classes.py +++ b/src/Python/tests/test_classes.py @@ -85,14 +85,14 @@ def get_class_methods(cls): methods = [item[0] for item in inspect.getmembers(cls, predicate=inspect.ismethod) if item[0] not in _base_object] methods.extend([item[0] for item in inspect.getmembers(cls, predicate=inspect.isfunction) if item[0] not in _base_object]) - + #Remove python internal methods return (m for m in methods if not m.startswith("__")) - + def get_class_properties(cls): """Gets all the properties in a class. - + https://stackoverflow.com/a/34643176. """ return [item[0] for item in inspect.getmembers(cls) @@ -144,9 +144,9 @@ def compare_names(dotnet_names: List[str], python_names: List[str]) -> str: # Count number of unique occurances python_set = set(python_normalized) # removes dupes dotnet_set = set(dotnet_normalized) # removes dupes - + message = "" - + # Check what names are missing from python but are available in dotnet python_lacks = [x for x in dotnet_set if x not in python_set] lacks_message_items = [f"({lacks_item}: (py:???->net:{dotnet_lookup[lacks_item]}))" for lacks_item in python_lacks] @@ -178,7 +178,7 @@ def compare_lists(expected, actual) -> str: def verify_enum(python_enum, dotnet_enum): """Verify that dotnet and python enum are the same - + Currently this is only verified working for 'int' type enums. But should be easily modified to support more types if needed """ @@ -221,7 +221,7 @@ def test_overloaded_missing(self): message = compare_names(dotnet_names, python_names) assert not message - + # region _generated from tableau_migration.migration import ( # noqa: E402, F401 @@ -231,6 +231,8 @@ def test_overloaded_missing(self): PyResult ) +from tableau_migration.migration_api_rest import PyRestIdentifiable # noqa: E402, F401 + from tableau_migration.migration_api_rest_models import ( # noqa: E402, F401 PyAdministratorLevels, PyContentPermissions, @@ -282,6 +284,19 @@ def test_overloaded_missing(self): PyPermissions ) +from tableau_migration.migration_content_schedules import ( # noqa: E402, F401 + PyExtractRefreshContentType, + PyExtractRefreshTask, + PyFrequencyDetails, + PyInterval, + PySchedule, + PyWithSchedule +) + +from tableau_migration.migration_content_schedules_cloud import PyCloudSchedule # noqa: E402, F401 + +from tableau_migration.migration_content_schedules_server import PyServerSchedule # noqa: E402, F401 + from tableau_migration.migration_engine import PyContentMigrationItem # noqa: E402, F401 from tableau_migration.migration_engine_actions import PyMigrationActionResult # noqa: E402, F401 @@ -317,12 +332,14 @@ def test_overloaded_missing(self): from Tableau.Migration.Api.Rest.Models.Types import DataSourceFileTypes from Tableau.Migration.Api.Rest.Models.Types import WorkbookFileTypes from Tableau.Migration.Content.Permissions import GranteeType +from Tableau.Migration.Content.Schedules import ExtractRefreshContentType from Tableau.Migration.Engine.Manifest import MigrationManifestEntryStatus _generated_class_data = [ (PyContentLocation, None), (PyContentReference, None), (PyResult, [ "CastFailure" ]), + (PyRestIdentifiable, None), (PyConnection, None), (PyConnectionsContent, None), (PyContainerContent, None), @@ -332,7 +349,7 @@ def test_overloaded_missing(self): (PyExtractContent, None), (PyGroup, [ "SetLocation" ]), (PyGroupUser, None), - (PyLabel, [ "Id" ]), + (PyLabel, None), (PyProject, [ "Container", "SetLocation" ]), (PyPublishableDataSource, [ "DisposeAsync", "File", "SetLocation" ]), (PyPublishableGroup, [ "SetLocation" ]), @@ -350,6 +367,13 @@ def test_overloaded_missing(self): (PyCapability, None), (PyGranteeCapability, None), (PyPermissions, None), + (PyExtractRefreshTask, None), + (PyFrequencyDetails, None), + (PyInterval, None), + (PySchedule, None), + (PyWithSchedule, None), + (PyCloudSchedule, None), + (PyServerSchedule, [ "ExtractRefreshTasks" ]), (PyContentMigrationItem, None), (PyMigrationActionResult, [ "CastFailure" ]), (PyContentMappingContext, [ "ToTask" ]), @@ -375,6 +399,7 @@ def test_overloaded_missing(self): (PyDataSourceFileTypes, DataSourceFileTypes), (PyWorkbookFileTypes, WorkbookFileTypes), (PyGranteeType, GranteeType), + (PyExtractRefreshContentType, ExtractRefreshContentType), (PyMigrationManifestEntryStatus, MigrationManifestEntryStatus) ] @@ -410,11 +435,11 @@ def test_classes(python_class, ignored_members): assert python_class._dotnet_base dotnet_class = python_class._dotnet_base - + # Get all the python methods and properties _all_py_methods = get_class_methods(python_class) _all_py_props = get_class_properties(python_class) - + # Get all the dotnet methods and properties _all_dotnet_methods = InteropHelper.GetMethods(dotnet_class) _all_dotnet_props = InteropHelper.GetProperties(dotnet_class) @@ -430,7 +455,7 @@ def test_classes(python_class, ignored_members): # Compare the lists method_message = compare_names(_clean_dotnet_method, _all_py_methods) prop_message = compare_names(_clean_dotnet_props, _all_py_props) - + # Assert assert not method_message # Remember that the names are normalize assert not prop_message # Remember that the names are normalize diff --git a/src/Python/tests/test_migration.py b/src/Python/tests/test_migration.py index 87695abb..1539137e 100644 --- a/src/Python/tests/test_migration.py +++ b/src/Python/tests/test_migration.py @@ -145,3 +145,107 @@ def test_path_segments(self): path = py.path_segments assert path == ["parent", "child", "item"] +# region _generated + +from enum import IntEnum # noqa: E402, F401 +from tableau_migration.migration_api_rest import PyRestIdentifiable # noqa: E402, F401 +from typing import Sequence # noqa: E402, F401 +from typing_extensions import Self # noqa: E402, F401 + +import System # noqa: E402 + +from Tableau.Migration import ( # noqa: E402, F401 + ContentLocation, + IContentReference, + IResult +) + +from tableau_migration.migration import ( # noqa: E402, F401 + PyContentLocation, + PyContentReference, + PyMigrationCompletionStatus, + PyResult +) + + +from Tableau.Migration import MigrationCompletionStatus + +# Extra imports for tests. +from tests.helpers.autofixture import AutoFixtureTestBase # noqa: E402, F401 + +class TestPyContentLocationGenerated(AutoFixtureTestBase): + + def test_ctor(self): + dotnet = self.create(ContentLocation) + py = PyContentLocation(dotnet) + assert py._dotnet == dotnet + + def test_path_segments_getter(self): + dotnet = self.create(ContentLocation) + py = PyContentLocation(dotnet) + assert len(dotnet.PathSegments) != 0 + assert len(py.path_segments) == len(dotnet.PathSegments) + + def test_path_separator_getter(self): + dotnet = self.create(ContentLocation) + py = PyContentLocation(dotnet) + assert py.path_separator == dotnet.PathSeparator + + def test_path_getter(self): + dotnet = self.create(ContentLocation) + py = PyContentLocation(dotnet) + assert py.path == dotnet.Path + + def test_name_getter(self): + dotnet = self.create(ContentLocation) + py = PyContentLocation(dotnet) + assert py.name == dotnet.Name + + def test_is_empty_getter(self): + dotnet = self.create(ContentLocation) + py = PyContentLocation(dotnet) + assert py.is_empty == dotnet.IsEmpty + +class TestPyContentReferenceGenerated(AutoFixtureTestBase): + + def test_ctor(self): + dotnet = self.create(IContentReference) + py = PyContentReference(dotnet) + assert py._dotnet == dotnet + + def test_content_url_getter(self): + dotnet = self.create(IContentReference) + py = PyContentReference(dotnet) + assert py.content_url == dotnet.ContentUrl + + def test_location_getter(self): + dotnet = self.create(IContentReference) + py = PyContentReference(dotnet) + assert py.location == None if dotnet.Location is None else PyContentLocation(dotnet.Location) + + def test_name_getter(self): + dotnet = self.create(IContentReference) + py = PyContentReference(dotnet) + assert py.name == dotnet.Name + +class TestPyResultGenerated(AutoFixtureTestBase): + + def test_ctor(self): + dotnet = self.create(IResult) + py = PyResult(dotnet) + assert py._dotnet == dotnet + + def test_success_getter(self): + dotnet = self.create(IResult) + py = PyResult(dotnet) + assert py.success == dotnet.Success + + def test_errors_getter(self): + dotnet = self.create(IResult) + py = PyResult(dotnet) + assert len(dotnet.Errors) != 0 + assert len(py.errors) == len(dotnet.Errors) + + +# endregion + diff --git a/src/Python/tests/test_migration_content.py b/src/Python/tests/test_migration_content.py index 07e3a8eb..e4ab88aa 100644 --- a/src/Python/tests/test_migration_content.py +++ b/src/Python/tests/test_migration_content.py @@ -122,6 +122,7 @@ def test_setter_empty(self): # region _generated from tableau_migration.migration import PyContentReference # noqa: E402, F401 +from tableau_migration.migration_api_rest import PyRestIdentifiable # noqa: E402, F401 from typing import ( # noqa: E402, F401 Sequence, List diff --git a/src/Python/tests/test_migration_content_permissions.py b/src/Python/tests/test_migration_content_permissions.py index f07879af..40bf3e1a 100644 --- a/src/Python/tests/test_migration_content_permissions.py +++ b/src/Python/tests/test_migration_content_permissions.py @@ -1,3 +1,18 @@ +# Copyright (c) 2024, Salesforce, Inc. +# SPDX-License-Identifier: Apache-2 +# +# 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. + # region _generated from enum import IntEnum # noqa: E402, F401 diff --git a/src/Tableau.Migration.PythonGenerator/ConversionMode.cs b/src/Tableau.Migration.PythonGenerator/ConversionMode.cs index e069ad45..1d5c52f0 100644 --- a/src/Tableau.Migration.PythonGenerator/ConversionMode.cs +++ b/src/Tableau.Migration.PythonGenerator/ConversionMode.cs @@ -33,6 +33,8 @@ internal enum ConversionMode WrapMutableCollection, - WrapArray + WrapArray, + + WrapTimeOnly } } diff --git a/src/Tableau.Migration.PythonGenerator/Generators/PythonMemberGenerator.cs b/src/Tableau.Migration.PythonGenerator/Generators/PythonMemberGenerator.cs index 1eef6e51..b7c04df6 100644 --- a/src/Tableau.Migration.PythonGenerator/Generators/PythonMemberGenerator.cs +++ b/src/Tableau.Migration.PythonGenerator/Generators/PythonMemberGenerator.cs @@ -62,7 +62,15 @@ internal abstract class PythonMemberGenerator Dotnet.Namespaces.SYSTEM_EXCEPTION, Dotnet.Namespaces.SYSTEM, ConversionMode.Direct); - + + private static readonly PythonTypeReference TIME_ONLY = new( + Py.Types.TIME, + ImportModule: Py.Modules.DATETIME, + ConversionMode.WrapTimeOnly, + DotNetParseFunction: "TimeOnly.Parse", + ExtraImports: ImmutableArray.Create( + new PythonTypeReference(Dotnet.Types.TIME_ONLY, ImportModule: Dotnet.Namespaces.SYSTEM, ConversionMode.Direct))); + private readonly PythonGeneratorOptions _options; protected PythonMemberGenerator(IOptions options) @@ -172,6 +180,8 @@ protected PythonTypeReference ToPythonType(ITypeSymbol t) case Dotnet.Types.STRING_SIMPLIFIED: case nameof(String): return STRING; + case nameof(TimeOnly): + return TIME_ONLY; default: if (t is IArrayTypeSymbol symbol) { diff --git a/src/Tableau.Migration.PythonGenerator/Keywords/Dotnet/Types.cs b/src/Tableau.Migration.PythonGenerator/Keywords/Dotnet/Types.cs index 74a6d4f4..b6374249 100644 --- a/src/Tableau.Migration.PythonGenerator/Keywords/Dotnet/Types.cs +++ b/src/Tableau.Migration.PythonGenerator/Keywords/Dotnet/Types.cs @@ -28,6 +28,7 @@ internal class Types public const string GUID = "Guid"; public const string LONG = "long"; public const string INT = "int"; + public const string TIME_ONLY = "TimeOnly"; } } diff --git a/src/Tableau.Migration.PythonGenerator/Keywords/Python/Modules.cs b/src/Tableau.Migration.PythonGenerator/Keywords/Python/Modules.cs index 4af52660..c708cb23 100644 --- a/src/Tableau.Migration.PythonGenerator/Keywords/Python/Modules.cs +++ b/src/Tableau.Migration.PythonGenerator/Keywords/Python/Modules.cs @@ -23,5 +23,6 @@ internal static class Modules public const string AUTOFIXTURE = "tests.helpers.autofixture"; public const string UUID = "uuid"; public const string TYPING = "typing"; + public const string DATETIME = "datetime"; } } \ No newline at end of file diff --git a/src/Tableau.Migration.PythonGenerator/Keywords/Python/Types.cs b/src/Tableau.Migration.PythonGenerator/Keywords/Python/Types.cs index 202de7b3..4ea9e090 100644 --- a/src/Tableau.Migration.PythonGenerator/Keywords/Python/Types.cs +++ b/src/Tableau.Migration.PythonGenerator/Keywords/Python/Types.cs @@ -27,5 +27,6 @@ internal static class Types public const string BOOL = "bool"; public const string STR = "str"; public const string INT = "int"; + public const string TIME = "time"; } } \ No newline at end of file diff --git a/src/Tableau.Migration.PythonGenerator/PythonGenerationList.cs b/src/Tableau.Migration.PythonGenerator/PythonGenerationList.cs index 5e65cddd..e9af5c0f 100644 --- a/src/Tableau.Migration.PythonGenerator/PythonGenerationList.cs +++ b/src/Tableau.Migration.PythonGenerator/PythonGenerationList.cs @@ -15,15 +15,17 @@ // limitations under the License. // -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis; +using Tableau.Migration.Api.Rest; using Tableau.Migration.Api.Rest.Models; using Tableau.Migration.Api.Rest.Models.Types; using Tableau.Migration.Content; using Tableau.Migration.Content.Permissions; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Engine; using Tableau.Migration.Engine.Actions; using Tableau.Migration.Engine.Hooks.Mappings; @@ -36,16 +38,27 @@ namespace Tableau.Migration.PythonGenerator { internal static class PythonGenerationList { - private static readonly ImmutableHashSet TYPES_TO_GENERATE = ToTypeNameHash( + private static readonly ImmutableHashSet TYPES_TO_GENERATE = GenerationListHelper.ToTypeNameHash( + #region - Tableau.Migration - + typeof(ContentLocation), + typeof(IRestIdentifiable), typeof(IContentReference), typeof(IResult), typeof(MigrationCompletionStatus), + #endregion + + #region - Tableau.Migration.Engine.Manifest - + typeof(MigrationManifestEntryStatus), typeof(IMigrationManifestEntry), typeof(IMigrationManifestEntryEditor), + #endregion + + #region - Tableau.Migration.Content - + typeof(IConnectionsContent), typeof(IContainerContent), typeof(IWithDomain), @@ -67,17 +80,53 @@ internal static class PythonGenerationList typeof(IGroupUser), typeof(IWorkbookDetails), typeof(ILabel), + typeof(IPublishableGroup), + typeof(IWithTags), + typeof(IWithOwner), + + #endregion + + #region - Tableau.Migration.Engine - typeof(ContentMigrationItem<>), + + #endregion + + #region - Tableau.Migration.Engine.Hooks.PostPublish - + typeof(ContentItemPostPublishContext<,>), + + #endregion + + #region - Tableau.Migration.Engine.Hooks.Mappings - + typeof(ContentMappingContext<>), + + #endregion + + #region - Tableau.Migration.Engine.Hooks.PostPublish - typeof(BulkPostPublishContext<>), + + #endregion + + #region - Tableau.Migration.Engine.Migrators - typeof(IContentItemMigrationResult<>), + + #endregion + + #region - Tableau.Migration.Engine.Migrators.Batch - + typeof(IContentBatchMigrationResult<>), + + #endregion + + #region - Tableau.Migration.Engine.Actions - + typeof(IMigrationActionResult), - typeof(IPublishableGroup), - typeof(IWithTags), - typeof(IWithOwner), + + #endregion + + #region - Tableau.Migration.Api.Rest.Models - typeof(AdministratorLevels), typeof(ContentPermissions), @@ -87,17 +136,49 @@ internal static class PythonGenerationList typeof(PermissionsCapabilityModes), typeof(PermissionsCapabilityNames), typeof(SiteRoles), + + #endregion + + #region - Tableau.Migration.Api.Rest.Models.Types - + typeof(AuthenticationTypes), typeof(DataSourceFileTypes), typeof(WorkbookFileTypes), + + #endregion + + #region - Tableau.Migration.Content.Permissions - + typeof(GranteeType), typeof(IGranteeCapability), typeof(IPermissions), - typeof(ICapability) - ); + typeof(ICapability), + + #endregion + + #region - Tableau.Migration.Content.Schedules - + + typeof(IInterval), + typeof(IFrequencyDetails), + typeof(ISchedule), + typeof(ExtractRefreshContentType), + typeof(IExtractRefreshTask<>), + typeof(IWithSchedule<>), + + #endregion + + #region - Tableau.Migration.Content.Schedules.Server - - private static ImmutableHashSet ToTypeNameHash(params Type[] types) - => types.Select(t => t.FullName!).ToImmutableHashSet(); + typeof(IServerSchedule), + + #endregion + + #region - Tableau.Migration.Content.Schedules.Cloud - + + typeof(ICloudSchedule) + + #endregion + ); private static IEnumerable FindTypesToGenerateForNamespace(INamespaceSymbol ns) { diff --git a/src/Tableau.Migration.PythonGenerator/PythonTypeReference.cs b/src/Tableau.Migration.PythonGenerator/PythonTypeReference.cs index a3c52a59..7e3ab070 100644 --- a/src/Tableau.Migration.PythonGenerator/PythonTypeReference.cs +++ b/src/Tableau.Migration.PythonGenerator/PythonTypeReference.cs @@ -35,7 +35,7 @@ public string GenericDefinitionName public bool IsExplicitReference => Name.Contains("."); - private static string ToPythonTypeName(ITypeSymbol dotNetType) + public static string ToPythonTypeName(ITypeSymbol dotNetType) { var typeName = dotNetType.Name; if (typeName.StartsWith("I")) diff --git a/src/Tableau.Migration.PythonGenerator/Tableau.Migration.PythonGenerator.csproj b/src/Tableau.Migration.PythonGenerator/Tableau.Migration.PythonGenerator.csproj index d26d1ba3..d7668df5 100644 --- a/src/Tableau.Migration.PythonGenerator/Tableau.Migration.PythonGenerator.csproj +++ b/src/Tableau.Migration.PythonGenerator/Tableau.Migration.PythonGenerator.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/src/Tableau.Migration.PythonGenerator/Writers/PythonConstructorTestWriter.cs b/src/Tableau.Migration.PythonGenerator/Writers/PythonConstructorTestWriter.cs index cf9b00b6..3de1fa2e 100644 --- a/src/Tableau.Migration.PythonGenerator/Writers/PythonConstructorTestWriter.cs +++ b/src/Tableau.Migration.PythonGenerator/Writers/PythonConstructorTestWriter.cs @@ -15,6 +15,9 @@ // limitations under the License. // +using Microsoft.CodeAnalysis; +using System.Linq; + namespace Tableau.Migration.PythonGenerator.Writers { internal sealed class PythonConstructorTestWriter : PythonMemberWriter, IPythonConstructorTestWriter @@ -37,8 +40,17 @@ private static void BuildCtorTestBody(PythonType type, IndentingStringBuilder ct var dotnetObj = "dotnet"; var pyObj = "py"; - ctorBuilder.AppendLine($"{dotnetObj} = self.create({type.DotNetType.Name})"); - ctorBuilder.AppendLine($"{pyObj} = {type.Name}({dotnetObj})"); + if (!type.DotNetType.IsGenericType) + { + ctorBuilder.AppendLine($"dotnet = self.create({type.DotNetType.Name})"); + ctorBuilder.AppendLine($"{pyObj} = {type.Name}({dotnetObj})"); + } + else + { + ctorBuilder.AppendLine($"dotnet = self.create({type.DotNetType.OriginalDefinition.Name}[{BuildDotnetGenericTypeConstraintsString(type.DotNetType)}])"); + ctorBuilder.AppendLine($"{pyObj} = {type.Name}[{BuildPythongGenericTypeConstraintsString(type.DotNetType)}]({dotnetObj})"); + } + ctorBuilder.AppendLine($"assert {pyObj}._dotnet == {dotnetObj}"); } } diff --git a/src/Tableau.Migration.PythonGenerator/Writers/PythonMemberWriter.cs b/src/Tableau.Migration.PythonGenerator/Writers/PythonMemberWriter.cs index 2414c2ec..386f39b4 100644 --- a/src/Tableau.Migration.PythonGenerator/Writers/PythonMemberWriter.cs +++ b/src/Tableau.Migration.PythonGenerator/Writers/PythonMemberWriter.cs @@ -16,7 +16,9 @@ // using System; +using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis; namespace Tableau.Migration.PythonGenerator.Writers { @@ -103,6 +105,8 @@ protected static string ToPythonType(PythonTypeReference typeRef, string express return BuildArrayWrapExpression(expression, mutableItemType.Name); case ConversionMode.Enum: return BuildWrapExpression(expression, wrapCtor, $"{expression}.value__"); + case ConversionMode.WrapTimeOnly: + return BuildWrapExpression(expression, wrapCtor, $"{expression}.Hour, {expression}.Minute, {expression}.Second, {expression}.Millisecond * 1000"); case ConversionMode.Direct: default: return expression; @@ -123,10 +127,24 @@ protected static string ToDotNetType(PythonTypeReference typeRef, string express return BuildWrapExpression(expression, $"{expression}.{PythonTypeWriter.DOTNET_OBJECT}"); case ConversionMode.WrapSerialized: return BuildWrapExpression(expression, typeRef.DotNetParseFunction!, $"str({expression})"); + case ConversionMode.WrapTimeOnly: + return BuildWrapExpression(expression, typeRef.DotNetParseFunction!, $"str({expression})"); case ConversionMode.Direct: default: return expression; } } + + protected static string BuildDotnetGenericTypeConstraintsString(INamedTypeSymbol dotnetType) + { + var typeConstraints = dotnetType.TypeParameters.First().ConstraintTypes; + return string.Join(",", typeConstraints.Select(t => t.Name)); + } + + protected static string BuildPythongGenericTypeConstraintsString(INamedTypeSymbol dotnetType) + { + var typeConstraints = dotnetType.TypeParameters.First().ConstraintTypes; + return string.Join(",", typeConstraints.Select(PythonTypeReference.ToPythonTypeName)); + } } } diff --git a/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyTestWriter.cs b/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyTestWriter.cs index 075824b1..29095958 100644 --- a/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyTestWriter.cs +++ b/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyTestWriter.cs @@ -15,6 +15,7 @@ // limitations under the License. // +using System; using System.Linq; using Microsoft.CodeAnalysis; @@ -22,16 +23,17 @@ namespace Tableau.Migration.PythonGenerator.Writers { internal sealed class PythonPropertyTestWriter : PythonMemberWriter, IPythonPropertyTestWriter { - public PythonPropertyTestWriter() - { } - public void Write(IndentingStringBuilder builder, PythonType type, PythonProperty property) { + var dotnetObj = "dotnet"; + var pyObj = "py"; + if (property.Getter) { using (var getterBuilder = builder.AppendLineAndIndent($"def test_{property.Name}_getter(self):")) { - BuildGetterTestBody(type, property, getterBuilder); + BuildTestBody(type, getterBuilder); + AddGetterAsserts(getterBuilder, dotnetObj, pyObj, property); } builder.AppendLine(); @@ -39,30 +41,39 @@ public void Write(IndentingStringBuilder builder, PythonType type, PythonPropert if (property.Setter) { - using (var getterBuilder = builder.AppendLineAndIndent($"def test_{property.Name}_setter(self):")) + using (var setterBuilder = builder.AppendLineAndIndent($"def test_{property.Name}_setter(self):")) { - BuildSetterTestBody(type, property, getterBuilder); + BuildTestBody(type, setterBuilder); + AddSetterAsserts(setterBuilder, dotnetObj, pyObj, property); } builder.AppendLine(); } - } - private static void BuildSetterTestBody(PythonType type, PythonProperty property, IndentingStringBuilder getterBuilder) + private static void BuildTestBody(PythonType type, IndentingStringBuilder builder) { var dotnetObj = "dotnet"; var pyObj = "py"; - getterBuilder.AppendLine($"{dotnetObj} = self.create({type.DotNetType.Name})"); - getterBuilder.AppendLine($"{pyObj} = {type.Name}({dotnetObj})"); - - AddSetterAsserts(getterBuilder, dotnetObj, pyObj, property); + if (!type.DotNetType.IsGenericType) + { + builder.AppendLine($"dotnet = self.create({type.DotNetType.Name})"); + builder.AppendLine($"{pyObj} = {type.Name}({dotnetObj})"); + } + else + { + builder.AppendLine( + $"dotnet = self.create({type.DotNetType.OriginalDefinition.Name}[{BuildDotnetGenericTypeConstraintsString(type.DotNetType)}])"); + builder.AppendLine( + $"{pyObj} = {type.Name}[{BuildPythongGenericTypeConstraintsString(type.DotNetType)}]({dotnetObj})"); + } } - private static void AddSetterAsserts(IndentingStringBuilder builder, string dotnetObj, string pyObj, PythonProperty property) + private static void AddSetterAsserts(IndentingStringBuilder builder, string dotnetObj, string pyObj, + PythonProperty property) { - string dotnetPropValue = $"{dotnetObj}.{property.DotNetProperty.Name}"; + var dotnetPropValue = $"{dotnetObj}.{property.DotNetProperty.Name}"; var pythonPropValue = $"{pyObj}.{property.Name}"; var typeRef = property.Type; @@ -72,88 +83,78 @@ private static void AddSetterAsserts(IndentingStringBuilder builder, string dotn case ConversionMode.WrapImmutableCollection: case ConversionMode.WrapMutableCollection: case ConversionMode.WrapArray: - { - builder.AppendLine($"assert len({dotnetPropValue}) != 0"); - builder.AppendLine($"assert len({pythonPropValue}) == len({dotnetPropValue})"); - builder.AppendLine(); - - builder.AppendLine("# create test data"); - - var dotnetType = property.DotNetProperty.Type; - - var element = dotnetType switch - { - INamedTypeSymbol dotnetNameType => dotnetNameType.TypeArguments.First().Name, - IArrayTypeSymbol dotnetArrayType => dotnetArrayType.ElementType.Name, - _ => throw new System.InvalidOperationException($"{dotnetType} is not supported."), - }; - - builder.AppendLine($"dotnetCollection = DotnetList[{element}]()"); + { + builder.AppendLine($"assert len({dotnetPropValue}) != 0"); + builder.AppendLine($"assert len({pythonPropValue}) == len({dotnetPropValue})"); + builder.AppendLine(); - for (var i = 1; i < 3; i++) - { - builder = builder.AppendLine($"dotnetCollection.Add(self.create({element}))"); - } + builder.AppendLine("# create test data"); - var collectionWrapExp = ToPythonType(typeRef, $"dotnetCollection"); - builder.AppendLine($"testCollection = {collectionWrapExp}"); - builder.AppendLine(); + var dotnetType = property.DotNetProperty.Type; - builder.AppendLine("# set property to new test value"); - builder.AppendLine($"{pythonPropValue} = testCollection"); - builder.AppendLine(); + var element = dotnetType switch + { + INamedTypeSymbol dotnetNameType => dotnetNameType.TypeArguments.First().Name, + IArrayTypeSymbol dotnetArrayType => dotnetArrayType.ElementType.Name, + _ => throw new InvalidOperationException($"{dotnetType} is not supported.") + }; - builder.AppendLine("# assert value"); - builder.AppendLine($"assert len({pythonPropValue}) == len(testCollection)"); + builder.AppendLine($"dotnetCollection = DotnetList[{element}]()"); - break; - } - default: + for (var i = 1; i < 3; i++) { - builder.AppendLine(); + builder = builder.AppendLine($"dotnetCollection.Add(self.create({element}))"); + } + + var collectionWrapExp = ToPythonType(typeRef, "dotnetCollection"); + builder.AppendLine($"testCollection = {collectionWrapExp}"); + builder.AppendLine(); - builder.AppendLine("# create test data"); + builder.AppendLine("# set property to new test value"); + builder.AppendLine($"{pythonPropValue} = testCollection"); + builder.AppendLine(); - var dotnetType = (INamedTypeSymbol)property.DotNetProperty.Type; + builder.AppendLine("# assert value"); + builder.AppendLine($"assert len({pythonPropValue}) == len(testCollection)"); - if (!dotnetType.IsGenericType) - { - builder.AppendLine($"testValue = self.create({dotnetType.Name})"); - } - else - { - var args = string.Join(", ", dotnetType.TypeArguments.Select(x => x.Name)); - builder.AppendLine($"testValue = self.create({dotnetType.OriginalDefinition.Name}[{args}])"); - } + break; + } + default: + { + builder.AppendLine(); - builder.AppendLine(); + builder.AppendLine("# create test data"); - var wrapExp = ToPythonType(typeRef, "testValue"); - builder.AppendLine("# set property to new test value"); - builder.AppendLine($"{pythonPropValue} = {wrapExp}"); - builder.AppendLine(); + var dotnetType = (INamedTypeSymbol)property.DotNetProperty.Type; - builder.AppendLine("# assert value"); - builder.AppendLine($"assert {pythonPropValue} == {wrapExp}"); - break; + if (!dotnetType.IsGenericType) + { + builder.AppendLine($"testValue = self.create({dotnetType.Name})"); + } + else + { + var args = string.Join(", ", dotnetType.TypeArguments.Select(x => x.Name)); + builder.AppendLine($"testValue = self.create({dotnetType.OriginalDefinition.Name}[{args}])"); } - } - } - private static void BuildGetterTestBody(PythonType type, PythonProperty property, IndentingStringBuilder getterBuilder) - { - var dotnetObj = "dotnet"; - var pyObj = "py"; + builder.AppendLine(); - getterBuilder.AppendLine($"{dotnetObj} = self.create({type.DotNetType.Name})"); - getterBuilder.AppendLine($"{pyObj} = {type.Name}({dotnetObj})"); + var wrapExp = ToPythonType(typeRef, "testValue"); + builder.AppendLine("# set property to new test value"); + builder.AppendLine($"{pythonPropValue} = {wrapExp}"); + builder.AppendLine(); - AddGetterAsserts(getterBuilder, dotnetObj, pyObj, property); + builder.AppendLine("# assert value"); + builder.AppendLine($"assert {pythonPropValue} == {wrapExp}"); + break; + } + } } - private static void AddGetterAsserts(IndentingStringBuilder builder, string dotnetObj, string pyObj, PythonProperty property) + private static void AddGetterAsserts(IndentingStringBuilder builder, string dotnetObj, string pyObj, + PythonProperty property) { - string dotnetPropValue = $"{dotnetObj}.{property.DotNetProperty.Name}"; + var dotnetPropValue = $"{dotnetObj}.{property.DotNetProperty.Name}"; var pythonPropValue = $"{pyObj}.{property.Name}"; var typeRef = property.Type; @@ -181,4 +182,4 @@ private static void AddGetterAsserts(IndentingStringBuilder builder, string dotn } } } -} +} \ No newline at end of file diff --git a/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyWriter.cs b/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyWriter.cs index 218cb3e3..b6982c4c 100644 --- a/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyWriter.cs +++ b/src/Tableau.Migration.PythonGenerator/Writers/PythonPropertyWriter.cs @@ -140,6 +140,12 @@ private void BuildSetterBody(PythonProperty property, IndentingStringBuilder set }); break; } + case ConversionMode.Enum: + { + var setterExpression = ToDotNetType(property.Type, paramName); + setterBuilder.AppendLine($"self.{PythonTypeWriter.DOTNET_OBJECT}.{property.DotNetProperty.Name}.value__ = {property.Type.Name}({setterExpression})"); + break; + } default: { var setterExpression = ToDotNetType(property.Type, paramName); diff --git a/src/Tableau.Migration.PythonGenerator/Writers/PythonTestWriter.cs b/src/Tableau.Migration.PythonGenerator/Writers/PythonTestWriter.cs index 9f1dd31e..c4853167 100644 --- a/src/Tableau.Migration.PythonGenerator/Writers/PythonTestWriter.cs +++ b/src/Tableau.Migration.PythonGenerator/Writers/PythonTestWriter.cs @@ -24,12 +24,9 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Options; -using Tableau.Migration.Content; -using Tableau.Migration.Content.Permissions; using Tableau.Migration.PythonGenerator.Config; -using Dotnet= Tableau.Migration.PythonGenerator.Keywords.Dotnet; -using Py = Tableau.Migration.PythonGenerator.Keywords.Python; using Tableau.Migration.PythonGenerator.Writers.Imports; +using Py = Tableau.Migration.PythonGenerator.Keywords.Python; namespace Tableau.Migration.PythonGenerator.Writers { @@ -201,69 +198,61 @@ private async ValueTask WriteWrapperCompletenessTestDataAsync(PythonTypeCache py WriteEnumCompletenessTestData(segment.StringBuilder, pyTypeCache); } - private async ValueTask WriteContentTypeWrapperTestsAsync(PythonTypeCache pyTypeCache, CancellationToken cancel) + private async ValueTask WriteClassMemberTests(PythonTypeCache pyTypeCache, CancellationToken cancel) { - var extraTestImports = new List() - { - new(Dotnet.Namespaces.TABLEAU_MIGRATION,new ImportedType(nameof(IContentReference))), - new(Dotnet.Namespaces.SYSTEM, [new ImportedType(Dotnet.Types.BOOLEAN), new ImportedType(Dotnet.Types.NULLABLE)]) - }; + var typesToTest = pyTypeCache + .Types + .Where(x => PythonTestGenerationList.ShouldGenerateTests(x.DotNetType)) + .ToList(); - await WriteTests($"{typeof(IUser).Namespace}", pyTypeCache, extraTestImports, cancel); + if (typesToTest == null || typesToTest.Count == 0) + { + return; + } - } + var namespaceGroups = typesToTest.GroupBy(x + => x.DotNetType?.ContainingNamespace.ToDisplayString() ?? string.Empty); - private async ValueTask WritePermissionsContentTypeWrapperTestsAsync(PythonTypeCache pyTypeCache, CancellationToken cancel) - { - var extraTestImports = new List() + foreach (var namespaceGroup in namespaceGroups) { - new(Dotnet.Namespaces.TABLEAU_MIGRATION,new ImportedType(nameof(IContentReference))), - new(Dotnet.Namespaces.SYSTEM,new ImportedType(Dotnet.Types.NULLABLE)), - new(Dotnet.Namespaces.SYSTEM_COLLECTIONS_GENERIC, new ImportedType(Dotnet.Types.LIST,Dotnet.TypeAliases.LIST)) - }; - await WriteTests($"{typeof(IPermissions).Namespace}", pyTypeCache, extraTestImports, cancel); - } + var classes = new PythonTypeCache(namespaceGroup.ToArray()); - private async Task WriteTests(string nameSpace, PythonTypeCache pyTypeCache, List extraTestImports, CancellationToken cancel) - { - var classes = new PythonTypeCache(pyTypeCache - .Types - .Where(x - => x.DotNetType?.ContainingNamespace?.ToDisplayString() != null - && x.DotNetType.ContainingNamespace.ToDisplayString() == nameSpace) - .ToArray()); - var moduleGroups = classes.Types.GroupBy(p => p.Module); - - foreach (var moduleGroup in moduleGroups) - { - var pyFileName = moduleGroup.Key.Replace("tableau_migration.", "") + ".py"; - var pyFilePath = Path.Combine(_testDirectoryPath, $"test_{pyFileName}"); + var moduleGroups = classes.Types.GroupBy(p => p.Module); - await using var segment = await GeneratedPythonSegment.OpenAsync(pyFilePath, cancel); + foreach (var moduleGroup in moduleGroups) + { + var pyFileName = moduleGroup.Key.Replace("tableau_migration.", "") + ".py"; + var pyFilePath = Path.Combine(_testDirectoryPath, $"test_{pyFileName}"); - WriteImports(segment.StringBuilder, moduleGroup.Key, moduleGroup); - var pythonTypes = moduleGroup.ToImmutableArray(); + await using var segment = await GeneratedPythonSegment.OpenAsync(pyFilePath, cancel); - WriteClassTestImports(segment.StringBuilder, new PythonTypeCache(pythonTypes)); + WriteImports(segment.StringBuilder, moduleGroup.Key, moduleGroup); + var pythonTypes = moduleGroup.ToImmutableArray(); - WriteExtraTestImports(segment.StringBuilder, extraTestImports); + WriteClassTestImports(segment.StringBuilder, new PythonTypeCache(pythonTypes)); - foreach (var pythonType in pythonTypes) - { - _classTestWriter.Write(segment.StringBuilder, pythonType); + WriteExtraTestImports(segment.StringBuilder, namespaceGroup.Key, pyTypeCache); + + foreach (var pythonType in pythonTypes) + { + _classTestWriter.Write(segment.StringBuilder, pythonType); + } } } } private static void WriteExtraTestImports( IndentingStringBuilder builder, - List extraTestImports) + string nameSpace, + PythonTypeCache pyTypeCache) { builder.AppendLine("# Extra imports for tests."); var autoFixtureNamespace = Py.Modules.AUTOFIXTURE; + var extraTestImports = PythonTestGenerationList.GetExtraImportsByNamespace(nameSpace, pyTypeCache); + if (!extraTestImports.Any(x => x.Name == autoFixtureNamespace)) { extraTestImports.Add(new ImportedModule(autoFixtureNamespace, new ImportedType(Py.Types.AUTOFIXTURE_TESTBASE))); @@ -282,8 +271,7 @@ private static void WriteExtraTestImports( public async ValueTask WriteAsync(PythonTypeCache pyTypeCache, CancellationToken cancel) { await WriteWrapperCompletenessTestDataAsync(pyTypeCache, cancel); - await WriteContentTypeWrapperTestsAsync(pyTypeCache, cancel); - await WritePermissionsContentTypeWrapperTestsAsync(pyTypeCache, cancel); + await WriteClassMemberTests(pyTypeCache, cancel); } } } diff --git a/src/Tableau.Migration/Api/ApiClient.cs b/src/Tableau.Migration/Api/ApiClient.cs index 4123e412..390dcd7b 100644 --- a/src/Tableau.Migration/Api/ApiClient.cs +++ b/src/Tableau.Migration/Api/ApiClient.cs @@ -15,13 +15,16 @@ // limitations under the License. // +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Tableau.Migration.Api.Models; +using Tableau.Migration.Api.Rest; using Tableau.Migration.Api.Rest.Models.Requests; using Tableau.Migration.Api.Rest.Models.Responses; using Tableau.Migration.Content; +using Tableau.Migration.Net; using Tableau.Migration.Net.Rest; using Tableau.Migration.Resources; @@ -32,6 +35,8 @@ internal sealed class ApiClient : ApiClientBase, IApiClient private readonly ISitesApiClient _sitesApiClient; private readonly TableauSiteConnectionConfiguration _siteConnectionConfiguration; private readonly IServerSessionProvider _sessionProvider; + private readonly IHttpContentSerializer _contentSerializer; + internal const string SITES_QUERY_NOT_SUPPORTED = "403069"; /// /// Creates a new object. @@ -43,6 +48,7 @@ internal sealed class ApiClient : ApiClientBase, IApiClient /// The logger factory to initialize from. /// The API client for site operations. /// A string localizer. + /// The content serializer. public ApiClient( IApiClientInput input, IRestRequestBuilderFactory restRequestBuilderFactory, @@ -50,17 +56,19 @@ public ApiClient( IServerSessionProvider sessionProvider, ILoggerFactory loggerFactory, ISitesApiClient sitesApiClient, - ISharedResourcesLocalizer sharedResourcesLocalizer) + ISharedResourcesLocalizer sharedResourcesLocalizer, + IHttpContentSerializer contentSerializer) : base(restRequestBuilderFactory, loggerFactory, sharedResourcesLocalizer) { _siteConnectionConfiguration = input.SiteConnectionConfiguration; _sessionProvider = sessionProvider; _sitesApiClient = sitesApiClient; + _contentSerializer = contentSerializer; tokenProvider.RefreshRequestedAsync += async (cancel) => { var signInResult = await GetSignInResultAsync(cancel).ConfigureAwait(false); - - if(!signInResult.Success) + + if (!signInResult.Success) { return signInResult.CastFailure(); } @@ -88,7 +96,9 @@ public async Task> SignInAsync(Cancellat return AsyncDisposableResult.Failed(signInResult.Errors); } - await _sessionProvider.SetCurrentUserAndSiteAsync(signInResult.Value, cancel).ConfigureAwait(false); + var instanceType = await GetInstanceTypeAsync(cancel).ConfigureAwait(false); + + await _sessionProvider.SetCurrentSessionAsync(signInResult.Value, instanceType, cancel).ConfigureAwait(false); return AsyncDisposableResult.Succeeded(_sitesApiClient); } @@ -107,6 +117,35 @@ private async Task> GetSignInResultAsync(CancellationToke return signInResult; } + internal async Task GetInstanceTypeAsync(CancellationToken cancel) + { + // The first version this endpoint is available. + // This is needed because we won't know the actual server version prior to this call. + const string MINIMUM_API_VERSION = "3.17"; // Tableau Server 2022.3 + + var sitesResult = await RestRequestBuilderFactory + .CreateUri("/sites") + .WithApiVersion(_sessionProvider.Version?.RestApiVersion ?? MINIMUM_API_VERSION) + .WithPage(1, 1) + .WithSiteId(null) + .ForGetRequest() + .SendAsync(cancel) + .ToResultAsync(_contentSerializer, SharedResourcesLocalizer, cancel) + .ConfigureAwait(false); + + if (sitesResult.Success) + { + return TableauInstanceType.Server; + } + + if (sitesResult.Errors.OfType().Any(e => e.Code == SITES_QUERY_NOT_SUPPORTED)) + { + return TableauInstanceType.Cloud; + } + + return TableauInstanceType.Unknown; + } + /// public async Task> GetServerInfoAsync(CancellationToken cancel) { diff --git a/src/Tableau.Migration/Api/ApiClientBase.cs b/src/Tableau.Migration/Api/ApiClientBase.cs index 6d2a7147..bc06546a 100644 --- a/src/Tableau.Migration/Api/ApiClientBase.cs +++ b/src/Tableau.Migration/Api/ApiClientBase.cs @@ -15,6 +15,8 @@ // limitations under the License. // +using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; using Tableau.Migration.Net.Rest; using Tableau.Migration.Resources; @@ -36,5 +38,30 @@ public ApiClientBase( Logger = loggerFactory.CreateLogger(GetType()); SharedResourcesLocalizer = sharedResourcesLocalizer; } + + public T ExecuteForInstanceType(TableauInstanceType expected, TableauInstanceType actual, Func executeIfSupported) + where T : notnull + { + if (AssertInstanceType(expected, actual, true)) + return executeIfSupported(); + + return default; + } + + public T ReturnForInstanceType(TableauInstanceType expected, TableauInstanceType actual, T returnValueWhenSupported) + where T : notnull + { + if (AssertInstanceType(expected, actual, true)) + return returnValueWhenSupported; + + return default; + } + + public bool AssertInstanceType(TableauInstanceType expected, TableauInstanceType actual, [DoesNotReturnIf(true)] bool throwOnFailure) + => actual == expected + ? true + : throwOnFailure + ? throw new TableauInstanceTypeNotSupportedException(actual, SharedResourcesLocalizer) + : false; } } diff --git a/src/Tableau.Migration/Api/DataSourcesApiClient.cs b/src/Tableau.Migration/Api/DataSourcesApiClient.cs index cf6fa5b5..1cf7c0a3 100644 --- a/src/Tableau.Migration/Api/DataSourcesApiClient.cs +++ b/src/Tableau.Migration/Api/DataSourcesApiClient.cs @@ -30,7 +30,6 @@ using Tableau.Migration.Api.Tags; using Tableau.Migration.Content; using Tableau.Migration.Content.Files; -using Tableau.Migration.Content.Permissions; using Tableau.Migration.Content.Search; using Tableau.Migration.Net.Rest; using Tableau.Migration.Net.Rest.Filtering; diff --git a/src/Tableau.Migration/Api/IApiClient.cs b/src/Tableau.Migration/Api/IApiClient.cs index b1782602..f31fe1f0 100644 --- a/src/Tableau.Migration/Api/IApiClient.cs +++ b/src/Tableau.Migration/Api/IApiClient.cs @@ -30,21 +30,21 @@ public interface IApiClient /// /// Signs into Tableau Server. /// - /// The cancellation token. + /// The cancellation token to obey. /// An authenticated . Task> SignInAsync(CancellationToken cancel); /// /// Gets the version information for the Tableau Server. /// - /// The cancellation token. + /// The cancellation token to obey. /// The information for the current Tableau Server. Task> GetServerInfoAsync(CancellationToken cancel); /// /// Gets the current session information. /// - /// The cancellation token. + /// The cancellation token to obey. /// The session information. Task> GetCurrentServerSessionAsync(CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IApiPageAccessor.cs b/src/Tableau.Migration/Api/IApiPageAccessor.cs index 18ea954d..9f09b568 100644 --- a/src/Tableau.Migration/Api/IApiPageAccessor.cs +++ b/src/Tableau.Migration/Api/IApiPageAccessor.cs @@ -32,7 +32,7 @@ public interface IApiPageAccessor : IContentApiClient /// /// The 1-indexed page number for the page to list. /// The expected maximum number of items to include in the page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The paged results. Task> GetPageAsync(int pageNumber, int pageSize, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IAuthenticationTokenProvider.cs b/src/Tableau.Migration/Api/IAuthenticationTokenProvider.cs index 1a2f1eed..ccf4ca31 100644 --- a/src/Tableau.Migration/Api/IAuthenticationTokenProvider.cs +++ b/src/Tableau.Migration/Api/IAuthenticationTokenProvider.cs @@ -33,7 +33,7 @@ public interface IAuthenticationTokenProvider /// /// Gets the authentication token. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// A task to await for the current authentication token. Task GetAsync(CancellationToken cancel); @@ -41,14 +41,14 @@ public interface IAuthenticationTokenProvider /// Sets the authentication token. /// /// The authentication token received from the server. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The task to await. Task SetAsync(string token, CancellationToken cancel); /// /// Clears the authentication token. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The task to await. Task ClearAsync(CancellationToken cancel); @@ -59,7 +59,7 @@ public interface IAuthenticationTokenProvider /// The token that was previously used before the refresh was requested. /// Used to de-duplicate refresh requests. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The task to await. Task RequestRefreshAsync(string? previousToken, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IBatchPublishApiClient.cs b/src/Tableau.Migration/Api/IBatchPublishApiClient.cs index 44517d61..a43e5133 100644 --- a/src/Tableau.Migration/Api/IBatchPublishApiClient.cs +++ b/src/Tableau.Migration/Api/IBatchPublishApiClient.cs @@ -31,7 +31,7 @@ public interface IBatchPublishApiClient : IContentApiClient /// Publishes a batch of content items. /// /// The content items to publish. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the publishing. Task PublishBatchAsync(IEnumerable items, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IConnectionManager.cs b/src/Tableau.Migration/Api/IConnectionManager.cs index 827954c7..a6f355cc 100644 --- a/src/Tableau.Migration/Api/IConnectionManager.cs +++ b/src/Tableau.Migration/Api/IConnectionManager.cs @@ -34,7 +34,7 @@ public interface IConnectionManager /// /// The URL prefix of the content item to get connections for. /// The ID of the content item to get connections for. - /// + /// The cancellation token to obey. /// Task>> ListConnectionsAsync( string urlPrefix, diff --git a/src/Tableau.Migration/Api/IContentFileStoreExtensions.cs b/src/Tableau.Migration/Api/IContentFileStoreExtensions.cs index f1d81e30..396dbf8b 100644 --- a/src/Tableau.Migration/Api/IContentFileStoreExtensions.cs +++ b/src/Tableau.Migration/Api/IContentFileStoreExtensions.cs @@ -30,7 +30,7 @@ internal static class IContentFileStoreExtensions /// The file store to save to. /// The content item to resolve a relative file store path from. /// The downloaded file. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A handle to the newly created file. public static async Task CreateAsync(this IContentFileStore store, T contentItem, FileDownload download, CancellationToken cancel) => await store.CreateAsync(contentItem, download.Filename ?? string.Empty, download.Content, cancel).ConfigureAwait(false); diff --git a/src/Tableau.Migration/Api/IContentReferenceFinderFactoryExtensions.cs b/src/Tableau.Migration/Api/IContentReferenceFinderFactoryExtensions.cs index 3e7955a1..3060f584 100644 --- a/src/Tableau.Migration/Api/IContentReferenceFinderFactoryExtensions.cs +++ b/src/Tableau.Migration/Api/IContentReferenceFinderFactoryExtensions.cs @@ -23,6 +23,8 @@ using Tableau.Migration.Api.Rest; using Tableau.Migration.Api.Rest.Models; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Resources; @@ -53,8 +55,8 @@ internal static class IContentReferenceFinderFactoryExtensions logger.LogWarning(localizer[SharedResourceKeys.ProjectReferenceNotFoundMessage], response.Project.Name, response.GetType().Name, response.Name); - return throwIfNotFound - ? throw new InvalidOperationException($"The project with ID {projectId} was not found.") + return throwIfNotFound + ? throw new InvalidOperationException($"The project with ID {projectId} was not found.") : null; } @@ -85,5 +87,35 @@ internal static class IContentReferenceFinderFactoryExtensions ? throw new InvalidOperationException($"The owner with ID {ownerId} was not found.") : null; } + + public static async Task FindScheduleAsync( + this IContentReferenceFinderFactory finderFactory, + [NotNull] IWithScheduleReferenceType? response, + CancellationToken cancel) + { + Guard.AgainstNull(response, nameof(response)); + + var schedule = Guard.AgainstNull(response.Schedule, () => nameof(response.Schedule)); + var scheduleId = Guard.AgainstDefaultValue(schedule.Id, () => nameof(response.Schedule.Id)); + + var scheduleFinder = finderFactory.ForContentType(); + + var foundSchedule = await scheduleFinder.FindByIdAsync(scheduleId, cancel).ConfigureAwait(false); + + return Guard.AgainstNull(foundSchedule, nameof(foundSchedule)); + } + + public static async Task FindExtractRefreshContentAsync( + this IContentReferenceFinderFactory finderFactory, + ExtractRefreshContentType contentType, + Guid contentId, + CancellationToken cancel) + { + var finder = finderFactory.ForExtractRefreshContent(contentType); + + var content = await finder.FindByIdAsync(contentId, cancel).ConfigureAwait(false); + + return Guard.AgainstNull(content, nameof(content)); + } } } diff --git a/src/Tableau.Migration/Api/IDataSourcesApiClient.cs b/src/Tableau.Migration/Api/IDataSourcesApiClient.cs index 669043e5..059e9aad 100644 --- a/src/Tableau.Migration/Api/IDataSourcesApiClient.cs +++ b/src/Tableau.Migration/Api/IDataSourcesApiClient.cs @@ -46,7 +46,7 @@ public interface IDataSourcesApiClient /// /// The 1-indexed page number. /// The size of the page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A list of a page of data sources in the current site. Task> GetAllPublishedDataSourcesAsync( int pageNumber, @@ -57,7 +57,7 @@ Task> GetAllPublishedDataSourcesAsync( /// Gets a data source by the given ID. /// /// The ID to get the data source for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The data source result. Task> GetDataSourceAsync( Guid dataSourceId, @@ -68,7 +68,7 @@ Task> GetDataSourceAsync( /// /// The ID to download the data source file for. /// Whether or not to include extracts in the data source file. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The file download result. Task> DownloadDataSourceAsync( Guid dataSourceId, @@ -79,7 +79,7 @@ Task> DownloadDataSourceAsync( /// Uploads the input data source file. /// /// The new data source's details. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The published data source. Task> PublishDataSourceAsync( IPublishDataSourceOptions options, @@ -89,7 +89,7 @@ Task> PublishDataSourceAsync( /// Updates the data source after publishing. /// /// The ID for the data source to update. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The new name of a the data source, or null to not update the name. /// The LUID of a project to move the data source to, or null to not update the project. /// The LUID of a user to assign the data source to as owner, or null to not update the owner. diff --git a/src/Tableau.Migration/Api/IGroupsApiClient.cs b/src/Tableau.Migration/Api/IGroupsApiClient.cs index 7181a81a..49536898 100644 --- a/src/Tableau.Migration/Api/IGroupsApiClient.cs +++ b/src/Tableau.Migration/Api/IGroupsApiClient.cs @@ -35,7 +35,7 @@ public interface IGroupsApiClient : /// /// The new group's name. /// The new group's minimum site role. - /// The cancellation token. + /// The cancellation token to obey. /// The newly created group. Task> CreateLocalGroupAsync(string name, string? minimumSiteRole, CancellationToken cancel); @@ -46,7 +46,7 @@ public interface IGroupsApiClient : /// The Active Directory domain name. /// The new group's minimum site role. /// The mode for automatically applying licenses for group members. - /// The cancellation token. + /// The cancellation token to obey. /// The newly created group. Task> ImportGroupFromActiveDirectoryAsync( string name, @@ -62,7 +62,7 @@ Task> ImportGroupFromActiveDirectoryAsync( /// The Active Directory domain name. /// The new group's minimum site role. /// The mode for automatically applying licenses for group members. - /// The cancellation token. + /// The cancellation token to obey. /// The newly created group. Task> ImportGroupFromActiveDirectoryBackgroundProcessAsync( string name, @@ -76,7 +76,7 @@ Task> ImportGroupFromActiveDirectoryBackgroundProcessAsync( /// /// The 1-indexed page number. /// The size of the page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A list of a page of groups in the current site. Task> GetAllGroupsAsync(int pageNumber, int pageSize, CancellationToken cancel); @@ -86,7 +86,7 @@ Task> ImportGroupFromActiveDirectoryBackgroundProcessAsync( /// The group's ID /// The 1-indexed page number. /// The size of the page. - /// The cancellation token. + /// The cancellation token to obey. /// A list of users for the given group ID Task> GetGroupUsersAsync(Guid groupId, int pageNumber, int pageSize, CancellationToken cancel); @@ -95,7 +95,7 @@ Task> ImportGroupFromActiveDirectoryBackgroundProcessAsync( /// /// The ID of the group the user should belong to. /// The user's ID. - /// The cancellation token. + /// The cancellation token to obey. /// The operation result. Task> AddUserToGroupAsync(Guid groupId, Guid userId, CancellationToken cancel); @@ -104,7 +104,7 @@ Task> ImportGroupFromActiveDirectoryBackgroundProcessAsync( /// /// The id of the group the user belongs to. /// The user-id. - /// The cancellation token. + /// The cancellation token to obey. /// The operation result. Task RemoveUserFromGroupAsync(Guid groupId, Guid userId, CancellationToken cancel); @@ -112,7 +112,7 @@ Task> ImportGroupFromActiveDirectoryBackgroundProcessAsync( /// Deletes a group. /// /// The id of the group to delete. - /// The cancellation token. + /// The cancellation token to obey. /// Task DeleteGroupAsync(Guid groupId, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IJobsApiClient.cs b/src/Tableau.Migration/Api/IJobsApiClient.cs index e9862b3d..b1cf225e 100644 --- a/src/Tableau.Migration/Api/IJobsApiClient.cs +++ b/src/Tableau.Migration/Api/IJobsApiClient.cs @@ -28,19 +28,19 @@ namespace Tableau.Migration.Api public interface IJobsApiClient : IContentApiClient { /// - /// Gets the status for a given job ID + /// Gets the status for a given job ID. /// - /// The job's ID - /// The cancellation token - /// The status for the given job ID + /// The job's ID. + /// The cancellation token to obey. + /// The status for the given job ID. Task> GetJobStatusAsync(Guid jobId, CancellationToken cancel); /// /// Waits for the job with the given ID to complete. /// - /// The job's ID - /// The cancellation token - /// The status for the given job ID + /// The job's ID. + /// The cancellation token to obey. + /// The status for the given job ID. Task WaitForJobAsync(Guid jobId, CancellationToken cancel); } } diff --git a/src/Tableau.Migration/Api/IOwnershipApiClient.cs b/src/Tableau.Migration/Api/IOwnershipApiClient.cs index 18592ac8..fda25521 100644 --- a/src/Tableau.Migration/Api/IOwnershipApiClient.cs +++ b/src/Tableau.Migration/Api/IOwnershipApiClient.cs @@ -31,7 +31,7 @@ public interface IOwnershipApiClient /// /// The ID of content item to change the owner. /// The new owner identificator. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of changing the item ownership. Task ChangeOwnerAsync(Guid contentItemId, Guid newOwnerId, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IPagedListApiClient.cs b/src/Tableau.Migration/Api/IPagedListApiClient.cs index eab48676..9226adcd 100644 --- a/src/Tableau.Migration/Api/IPagedListApiClient.cs +++ b/src/Tableau.Migration/Api/IPagedListApiClient.cs @@ -39,7 +39,7 @@ public interface IPagedListApiClient : IContentApiClient /// Gets all the content items that the user has access to. /// /// The expected maximum number of items to include in each page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The total results. public async Task>> GetAllAsync(int pageSize, CancellationToken cancel) => await GetPager(pageSize).GetAllPagesAsync(cancel).ConfigureAwait(false); diff --git a/src/Tableau.Migration/Api/IProjectsApiClient.cs b/src/Tableau.Migration/Api/IProjectsApiClient.cs index 489d4f1c..5f75920f 100644 --- a/src/Tableau.Migration/Api/IProjectsApiClient.cs +++ b/src/Tableau.Migration/Api/IProjectsApiClient.cs @@ -38,7 +38,7 @@ public interface IProjectsApiClient : IContentApiClient, /// Creates a project. /// /// The new project's details. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The newly created project. Task> CreateProjectAsync( ICreateProjectOptions options, @@ -48,7 +48,7 @@ Task> CreateProjectAsync( /// Gets the project's default permissions. /// /// The project ID. - /// A cancellation token to obey. + /// The cancellation token to obey. Task>> GetAllDefaultPermissionsAsync( Guid projectId, CancellationToken cancel); @@ -58,7 +58,7 @@ Task>> GetAllDefaultPermissio /// /// The project ID. /// The new permissions. - /// A cancellation token to obey. + /// The cancellation token to obey. Task>> UpdateAllDefaultPermissionsAsync( Guid projectId, IReadOnlyDictionary permissions, @@ -68,7 +68,7 @@ Task>> UpdateAllDefaultPermis /// Updates the project after publishing. /// /// The ID for the project to update. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The new name of the project, or null to not update the name. /// The new description of the project, or null to not update the description. /// @@ -96,7 +96,7 @@ public Task> UpdateProjectAsync( /// Deletes a project. /// /// The ID for the project to delete. - /// A cancellation token to obey. + /// The cancellation token to obey. public Task DeleteProjectAsync(Guid projectId, CancellationToken cancel); } } diff --git a/src/Tableau.Migration/Api/IPublishApiClient.cs b/src/Tableau.Migration/Api/IPublishApiClient.cs index 73248368..0c21b74c 100644 --- a/src/Tableau.Migration/Api/IPublishApiClient.cs +++ b/src/Tableau.Migration/Api/IPublishApiClient.cs @@ -32,7 +32,7 @@ public interface IPublishApiClient /// Publishes a content item. /// /// The content item to publish. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the publishing with a content reference of the newly published item. Task> PublishAsync(TPublish item, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IPullApiClient.cs b/src/Tableau.Migration/Api/IPullApiClient.cs index 5ab834e4..a5970628 100644 --- a/src/Tableau.Migration/Api/IPullApiClient.cs +++ b/src/Tableau.Migration/Api/IPullApiClient.cs @@ -32,7 +32,7 @@ public interface IPullApiClient /// Pulls enough information to publish the content item. /// /// The content item to pull. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the pull operation with the item to publish. Task> PullAsync(TContent contentItem, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IReadApiClient.cs b/src/Tableau.Migration/Api/IReadApiClient.cs index 4d7d38a3..f6ed9b2c 100644 --- a/src/Tableau.Migration/Api/IReadApiClient.cs +++ b/src/Tableau.Migration/Api/IReadApiClient.cs @@ -32,7 +32,7 @@ public interface IReadApiClient /// Gets the content item by Id. /// /// The content item Id to get. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the get operation with the content item. Task> GetByIdAsync(Guid contentId, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IServerSessionProvider.cs b/src/Tableau.Migration/Api/IServerSessionProvider.cs index 6ec1bec6..78cb38dc 100644 --- a/src/Tableau.Migration/Api/IServerSessionProvider.cs +++ b/src/Tableau.Migration/Api/IServerSessionProvider.cs @@ -48,30 +48,37 @@ public interface IServerSessionProvider Guid? UserId { get; } /// - /// Sets the current user and site information. + /// The type of Tableau instance connected to. One of the values in . + /// + TableauInstanceType InstanceType { get; } + + /// + /// Sets the current session information. /// /// The sign-in result containing the current user and site information. + /// The instance type connected to. It can be one of . /// The cancellation token to obey. /// The task to await. - Task SetCurrentUserAndSiteAsync(ISignInResult signInResult, CancellationToken cancel); + Task SetCurrentSessionAsync(ISignInResult signInResult, TableauInstanceType instanceType, CancellationToken cancel); /// - /// Sets the current user and site information. + /// Sets the current session information. /// /// The current user's ID. /// The current site's ID. /// The current site's content URL. /// The current user's authentication token. + /// The instance type connected to. It can be one of . /// The cancellation token to obey. /// The task to await. - Task SetCurrentUserAndSiteAsync(Guid userId, Guid siteId, string siteContentUrl, string authenticationToken, CancellationToken cancel); + Task SetCurrentSessionAsync(Guid userId, Guid siteId, string siteContentUrl, string authenticationToken, TableauInstanceType instanceType, CancellationToken cancel); /// - /// Clears the current user and site information. + /// Clears the current session information. /// /// The cancellation token to obey. /// The task to await. - Task ClearCurrentUserAndSiteAsync(CancellationToken cancel); + Task ClearCurrentSessionAsync(CancellationToken cancel); /// /// Sets the current version information. diff --git a/src/Tableau.Migration/Api/IServiceCollectionExtensions.cs b/src/Tableau.Migration/Api/IServiceCollectionExtensions.cs index 46e1865b..a65b1c57 100644 --- a/src/Tableau.Migration/Api/IServiceCollectionExtensions.cs +++ b/src/Tableau.Migration/Api/IServiceCollectionExtensions.cs @@ -25,6 +25,8 @@ using Tableau.Migration.Api.Simulation; using Tableau.Migration.Api.Tags; using Tableau.Migration.Content.Files; +using Tableau.Migration.Content.Schedules.Server; +using Tableau.Migration.Content.Search; using Tableau.Migration.Net; using Tableau.Migration.Net.Simulation; @@ -66,11 +68,13 @@ internal static IServiceCollection AddMigrationApiClient(this IServiceCollection services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); //API Simulator. services.AddSingleton(); @@ -89,6 +93,14 @@ internal static IServiceCollection AddMigrationApiClient(this IServiceCollection services.AddScoped(p => p.GetRequiredService().ContentReferenceFinderFactory); services.AddScoped(typeof(BulkApiContentReferenceCache<>)); + //Content caches + services.AddScoped(); + + //Server schedules content cache + services.AddScoped>(); + services.AddScoped>(p => p.GetRequiredService>()); + services.AddScoped>(p => p.GetRequiredService>()); + //Non-Engine content file services. services.AddSingleton(); services.AddSingleton(); diff --git a/src/Tableau.Migration/Api/ISitesApiClient.cs b/src/Tableau.Migration/Api/ISitesApiClient.cs index 33b1b50c..c3a7f30f 100644 --- a/src/Tableau.Migration/Api/ISitesApiClient.cs +++ b/src/Tableau.Migration/Api/ISitesApiClient.cs @@ -60,7 +60,7 @@ public interface ISitesApiClient : IAsyncDisposable, IContentApiClient IWorkbooksApiClient Workbooks { get; } /// - /// Gets the API client for views operations. + /// Gets the API client for view operations. /// IViewsApiClient Views { get; } @@ -69,11 +69,26 @@ public interface ISitesApiClient : IAsyncDisposable, IContentApiClient /// IFlowsApiClient Flows { get; } + /// + /// Gets the API client for schedule operations. + /// + ISchedulesApiClient Schedules { get; } + + /// + /// Gets the API client for Tableau Server task operations. + /// + IServerTasksApiClient ServerTasks { get; } + + /// + /// Gets the API client for Tableau Cloud task operations. + /// + ICloudTasksApiClient CloudTasks { get; } + /// /// Gets the site with the specified ID. /// /// The site's ID. - /// The cancellation token. + /// The cancellation token to obey. /// The site with the specified ID. Task> GetSiteAsync(Guid siteId, CancellationToken cancel); @@ -81,7 +96,7 @@ public interface ISitesApiClient : IAsyncDisposable, IContentApiClient /// Gets the site with the specified content URL. /// /// The site's content URL. - /// The cancellation token. + /// The cancellation token to obey. /// The site with the specified content URL. Task> GetSiteAsync(string contentUrl, CancellationToken cancel); @@ -89,7 +104,7 @@ public interface ISitesApiClient : IAsyncDisposable, IContentApiClient /// Updates the site. /// /// The settings to update on the site.. - /// The cancellation token. + /// The cancellation token to obey. /// The site information returned after the update. Task> UpdateSiteAsync(ISiteSettingsUpdate update, CancellationToken cancel); diff --git a/src/Tableau.Migration/Api/IUsersApiClient.cs b/src/Tableau.Migration/Api/IUsersApiClient.cs index a28cce44..156d475e 100644 --- a/src/Tableau.Migration/Api/IUsersApiClient.cs +++ b/src/Tableau.Migration/Api/IUsersApiClient.cs @@ -37,7 +37,7 @@ public interface IUsersApiClient : IContentApiClient, IPagedListApiClient /// The user's ID. /// The 1-indexed page number. /// The size of the page. - /// The cancellation token + /// The cancellation token to obey. /// A list of groups for the given user ID Task> GetUserGroupsAsync(Guid userId, int pageNumber, int pageSize, CancellationToken cancel); @@ -46,7 +46,7 @@ public interface IUsersApiClient : IContentApiClient, IPagedListApiClient /// /// The 1-indexed page number. /// The size of the page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A list of a page of users in the current site. Task> GetAllUsersAsync(int pageNumber, int pageSize, CancellationToken cancel); @@ -55,7 +55,7 @@ public interface IUsersApiClient : IContentApiClient, IPagedListApiClient /// /// The users to include in the request payload. /// The in-memory stream containing user data in a csv format. - /// The cancellation token. + /// The cancellation token to obey. /// The newly created import job. Task> ImportUsersAsync(IEnumerable users, Stream csvStream, CancellationToken cancel); @@ -65,7 +65,7 @@ public interface IUsersApiClient : IContentApiClient, IPagedListApiClient /// The username. In case of Tableau Cloud, the user name is the email address of the user. /// The site role for the user. /// The optional authentication type of the user. - /// The cancellation token. + /// The cancellation token to obey. /// Task> AddUserAsync(string userName, string siteRole, string? authenticationType, CancellationToken cancel); @@ -74,7 +74,7 @@ public interface IUsersApiClient : IContentApiClient, IPagedListApiClient /// /// The Identifier for the user. /// The new Site Role for the user. - /// The cancellation token. + /// The cancellation token to obey. /// (Optional) The new Full Name for the user. /// (Optional) The new email address for the user. /// (Optional) The new password for the user. @@ -93,7 +93,7 @@ Task> UpdateUserAsync(Guid id, /// Deletes a user. /// /// The user's ID. - /// The cancellation token. + /// The cancellation token to obey. /// Task DeleteUserAsync(Guid userId, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/IWorkbooksApiClient.cs b/src/Tableau.Migration/Api/IWorkbooksApiClient.cs index 28f2f328..c493d0ba 100644 --- a/src/Tableau.Migration/Api/IWorkbooksApiClient.cs +++ b/src/Tableau.Migration/Api/IWorkbooksApiClient.cs @@ -44,7 +44,7 @@ public interface IWorkbooksApiClient : /// /// The 1-indexed page number. /// The size of the page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A list of a page of workbooks in the current site. Task> GetAllWorkbooksAsync(int pageNumber, int pageSize, CancellationToken cancel); @@ -52,7 +52,7 @@ public interface IWorkbooksApiClient : /// Gets a workbook by the given ID. /// /// The ID to get the workbook for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The data sorce result. Task> GetWorkbookAsync(Guid workbookId, CancellationToken cancel); @@ -61,7 +61,7 @@ public interface IWorkbooksApiClient : /// /// The ID to download the workbook file for. /// Whether or not to include extracts in the workbook file. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The file download result. Task> DownloadWorkbookAsync( Guid workbookId, @@ -72,7 +72,7 @@ Task> DownloadWorkbookAsync( /// Uploads the input workbook file. /// /// The new workbook's details. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The published workbook. Task> PublishWorkbookAsync( IPublishWorkbookOptions options, @@ -82,7 +82,7 @@ Task> PublishWorkbookAsync( /// Updates the workbook after publishing. /// /// The ID for the workbook to update. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The new name of the workbook, or null to not update the name. /// The new description of the workbook, or null to not update the description. /// The LUID of a project to move the workbook to, or null to not update the project. diff --git a/src/Tableau.Migration/Api/JobsApiClient.cs b/src/Tableau.Migration/Api/JobsApiClient.cs index 41a4e075..641f622a 100644 --- a/src/Tableau.Migration/Api/JobsApiClient.cs +++ b/src/Tableau.Migration/Api/JobsApiClient.cs @@ -16,7 +16,6 @@ // using System; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/src/Tableau.Migration/Api/Labels/LabelsApiClient.cs b/src/Tableau.Migration/Api/Labels/LabelsApiClient.cs index 4cd9fdaa..6b0ac353 100644 --- a/src/Tableau.Migration/Api/Labels/LabelsApiClient.cs +++ b/src/Tableau.Migration/Api/Labels/LabelsApiClient.cs @@ -103,41 +103,33 @@ public async Task>> UpdateLabelsAsync( IEnumerable labels, CancellationToken cancel) { - var updateTasks = new List>>>(); + var resultBuilder = new ResultBuilder(); + var updatedLabels = new List(); foreach (var label in labels) { - var updateTask = UpdateLabelAsync( + var updateResult = await UpdateLabelAsync( contentItemId, _contentItemType, label, - cancel); - - updateTasks.Add(updateTask); - } + cancel) + .ConfigureAwait(false); - var updateResult = await Task.WhenAll(updateTasks).ConfigureAwait(false); + resultBuilder.Add(updateResult); - if (updateResult == null) - { - return Result>.Failed( - new Exception($"Failed to create/update one or more labels for {contentItemId}.")); - } + if (!updateResult.Success) + { + // Execute all updates like Task.WhenAll + continue; + } - if (!updateResult.All(r => r.Success)) - { - return Result>.Failed( - updateResult.SelectMany(r => r.Errors).ToArray()); + updatedLabels.AddRange(updateResult.Value); } + var result = resultBuilder.Build(); - - var updatedLabels = new List(); - foreach (var val in updateResult) + if (!result.Success) { - if (val.Value == null) - continue; - - updatedLabels.AddRange(val.Value); + return Result>.Failed(result.Errors); } return Result>.Succeeded(updatedLabels.Distinct().ToImmutableList()); diff --git a/src/Tableau.Migration/Api/Permissions/DefaultPermissionsApiClient.cs b/src/Tableau.Migration/Api/Permissions/DefaultPermissionsApiClient.cs index a3fb9d6a..18b8bc13 100644 --- a/src/Tableau.Migration/Api/Permissions/DefaultPermissionsApiClient.cs +++ b/src/Tableau.Migration/Api/Permissions/DefaultPermissionsApiClient.cs @@ -106,36 +106,22 @@ public async Task>> GetAllPer var defaultPermissions = ImmutableDictionary.CreateBuilder(StringComparer.OrdinalIgnoreCase); - var getPermissionsTasks = _contentTypeClients - .ToDictionary(c => c.Key, c => GetPermissionsAsync(c.Key, projectId, cancel)); + foreach (var contentTypeClient in _contentTypeClients) + { + var permissionResult = await GetPermissionsAsync(contentTypeClient.Key, projectId, cancel).ConfigureAwait(false); - var getPermissionsResults = await Task.WhenAll(getPermissionsTasks.Values).ConfigureAwait(false); + resultBuilder.Add(permissionResult); - if (getPermissionsResults is null) - { - resultBuilder.Add( - Result.Failed( - new Exception($"Failed to get default project permissions for one or more content types for {projectId}."))); - } - else - { - foreach (var getPermissionsTask in getPermissionsTasks) + if (!permissionResult.Success) { - var getPermissionsResult = getPermissionsTask.Value.Result; - - if (!getPermissionsResult.Success) - { - resultBuilder.Add(getPermissionsResult); - _logger.LogWarning( - new AggregateException(getPermissionsResult.Errors), - _localizer[SharedResourceKeys.FailedToGetDefaultPermissionsMessage], - getPermissionsTask.Key, - projectId); - continue; - } - - defaultPermissions.Add(getPermissionsTask.Key, getPermissionsResult.Value); + _logger.LogWarning( + new AggregateException(permissionResult.Errors), + _localizer[SharedResourceKeys.FailedToGetDefaultPermissionsMessage], + contentTypeClient.Key, + projectId); + continue; } + defaultPermissions.Add(contentTypeClient.Key, permissionResult.Value); } if (defaultPermissions.Any()) @@ -156,38 +142,25 @@ public async Task>> UpdateAll var updatedPermissions = ImmutableDictionary.CreateBuilder(StringComparer.OrdinalIgnoreCase); - var updatePermissionsTasks = new Dictionary>>(StringComparer.OrdinalIgnoreCase); - foreach (var permission in permissions) { - updatePermissionsTasks.Add(permission.Key, UpdatePermissionsAsync(permission.Key, projectId, permission.Value, cancel)); - } - - var updatePermissionsResults = await Task.WhenAll(updatePermissionsTasks.Values).ConfigureAwait(false); + var updatePermissionsResult = await UpdatePermissionsAsync(permission.Key, projectId, permission.Value, cancel).ConfigureAwait(false); - if (updatePermissionsResults is null) - { - resultBuilder.Add( - Result.Failed( - new Exception($"Failed to update default project permissions for one or more content types for {projectId}."))); - } - else - { - foreach (var updatePermissionsTask in updatePermissionsTasks) + resultBuilder.Add(updatePermissionsResult); + + if (!updatePermissionsResult.Success) { - var updatePermissionsResult = updatePermissionsTask.Value.Result; - - if (!updatePermissionsResult.Success) - resultBuilder.Add(updatePermissionsResult); - else - updatedPermissions.Add(updatePermissionsTask.Key, updatePermissionsResult.Value); + continue; } + updatedPermissions.Add(permission.Key, updatePermissionsResult.Value); } - + var result = resultBuilder.Build(); if (!result.Success) + { return Result>.Failed(result.Errors); + } return Result>.Succeeded(updatedPermissions.ToImmutable()); } diff --git a/src/Tableau.Migration/Api/Permissions/IDefaultPermissionsApiClient.cs b/src/Tableau.Migration/Api/Permissions/IDefaultPermissionsApiClient.cs index f19aa1ea..0630dac5 100644 --- a/src/Tableau.Migration/Api/Permissions/IDefaultPermissionsApiClient.cs +++ b/src/Tableau.Migration/Api/Permissions/IDefaultPermissionsApiClient.cs @@ -34,7 +34,7 @@ public interface IDefaultPermissionsApiClient /// /// The permissions' content type URL segment. /// The ID of the project. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task> GetPermissionsAsync( string contentTypeUrlSegment, @@ -45,7 +45,7 @@ Task> GetPermissionsAsync( /// Gets the default permissions for the project with the specified ID. /// /// The ID of the project. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with content type . Task>> GetAllPermissionsAsync( Guid projectId, @@ -57,7 +57,7 @@ Task>> GetAllPermissionsAsync /// The permissions' content type URL segment. /// The ID of the project. /// The permissions of the content item. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task> CreatePermissionsAsync( string contentTypeUrlSegment, @@ -73,7 +73,7 @@ Task> CreatePermissionsAsync( /// The id of the permissions grantee. This is either a user or group. /// The type of the permissions grantee. /// The object containing the capability name and mode. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Task DeleteCapabilityAsync( string contentTypeUrlSegment, @@ -89,7 +89,7 @@ Task DeleteCapabilityAsync( /// The permissions' content type URL segment. /// The ID of the project. /// - /// + /// The cancellation token to obey. /// Task DeleteAllPermissionsAsync( string contentTypeUrlSegment, @@ -103,7 +103,7 @@ Task DeleteAllPermissionsAsync( /// The permissions' content type URL segment. /// The ID of the project. /// The permissions of the content item. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task> UpdatePermissionsAsync( string contentTypeUrlSegment, @@ -116,7 +116,7 @@ Task> UpdatePermissionsAsync( /// /// The ID of the project. /// The permissions of the content items, keyed by the content type's URL segment. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task>> UpdateAllPermissionsAsync( Guid projectId, diff --git a/src/Tableau.Migration/Api/Permissions/IPermissionsApiClient.cs b/src/Tableau.Migration/Api/Permissions/IPermissionsApiClient.cs index 2e1cebaf..22fe99e9 100644 --- a/src/Tableau.Migration/Api/Permissions/IPermissionsApiClient.cs +++ b/src/Tableau.Migration/Api/Permissions/IPermissionsApiClient.cs @@ -31,7 +31,7 @@ public interface IPermissionsApiClient /// Gets the permissions for the content item with the specified ID. /// /// The ID of the content item. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task> GetPermissionsAsync( Guid contentItemId, @@ -42,7 +42,7 @@ Task> GetPermissionsAsync( /// /// The id of the content item. /// The permissions of the content item. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task> CreatePermissionsAsync( Guid contentItemId, @@ -56,7 +56,7 @@ Task> CreatePermissionsAsync( /// The id of the permissions grantee. This is either a user or group. /// The type of the permissions grantee. /// The object containing the capability name and mode. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Task DeleteCapabilityAsync( Guid contentItemId, @@ -70,7 +70,7 @@ Task DeleteCapabilityAsync( /// /// Id of the content item. /// - /// + /// The cancellation token to obey. /// Task DeleteAllPermissionsAsync( Guid contentItemId, @@ -82,7 +82,7 @@ Task DeleteAllPermissionsAsync( /// /// Id of the content item. /// The permissions of the content item. - /// The cancellation token. + /// The cancellation token to obey. /// The permissions result with . Task> UpdatePermissionsAsync( Guid contentItemId, diff --git a/src/Tableau.Migration/Api/Permissions/PermissionsApiClient.cs b/src/Tableau.Migration/Api/Permissions/PermissionsApiClient.cs index 714793a6..604609ff 100644 --- a/src/Tableau.Migration/Api/Permissions/PermissionsApiClient.cs +++ b/src/Tableau.Migration/Api/Permissions/PermissionsApiClient.cs @@ -16,7 +16,6 @@ // using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -130,7 +129,7 @@ public async virtual Task DeletePermissionsAsync( return Result.Succeeded(); } - var deleteTasks = new List>(); + var resultBuilder = new ResultBuilder(); foreach (var item in itemsToDelete) { @@ -138,30 +137,26 @@ public async virtual Task DeletePermissionsAsync( foreach (var capability in item.Capabilities) { - var deleteTask = DeleteCapabilityAsync( + var deleteResult = await DeleteCapabilityAsync( contentItemId, granteeId, item.GranteeType, capability, - cancel); + cancel) + .ConfigureAwait(false); - deleteTasks.Add(deleteTask); + if (!deleteResult.Success) + { + resultBuilder.Add(deleteResult); + } } } - var deleteResult = await Task.WhenAll(deleteTasks).ConfigureAwait(false); - - var deleteSuccesful = deleteResult is not null && deleteResult.All(r => r.Success); + var result = resultBuilder.Build(); - if (!deleteSuccesful) + if (!result.Success) { - var deleteErrors = deleteResult is null ? - new[] - { - new Exception($"Failed to delete one or more capabilities for {contentItemId}.") - } - : deleteResult.SelectMany(r => r.Errors).ToArray(); - return Result.Failed(deleteErrors); + return Result.Failed(result.Errors); } return Result.Succeeded(); } diff --git a/src/Tableau.Migration/Api/ProjectsApiClient.cs b/src/Tableau.Migration/Api/ProjectsApiClient.cs index 8687a188..b6f3d3c3 100644 --- a/src/Tableau.Migration/Api/ProjectsApiClient.cs +++ b/src/Tableau.Migration/Api/ProjectsApiClient.cs @@ -58,7 +58,7 @@ public ProjectsApiClient( { _defaultPermissionsClient = permissionsClientFactory.CreateDefaultPermissionsClient(); _serializer = serializer; - + Permissions = permissionsClientFactory.Create(this); } @@ -212,9 +212,9 @@ public async Task> PublishAsync(IProject item, CancellationTok // We don't need to load the parent project here since it's already published. // The owner may be different, though, which we'll want to know for the post-publish hook. - var existingProject = await RestProjectBuilder.BuildProjectAsync(existingProjectResult.Value[0], + var existingProject = await RestProjectBuilder.BuildProjectAsync(existingProjectResult.Value[0], item.ParentProject, UserFinder.Value, cancel).ConfigureAwait(false); - + return Result.Succeeded(existingProject); } diff --git a/src/Tableau.Migration/Api/Publishing/FilePublisherBase.cs b/src/Tableau.Migration/Api/Publishing/FilePublisherBase.cs index f081e90c..7d10c0e8 100644 --- a/src/Tableau.Migration/Api/Publishing/FilePublisherBase.cs +++ b/src/Tableau.Migration/Api/Publishing/FilePublisherBase.cs @@ -72,7 +72,7 @@ public FilePublisherBase( /// Publishes a stream to a given site and commits the upload. /// /// The publish options context object. - /// The cancellation token + /// The cancellation token to obey. /// The specified type object with the completion data. public async Task> PublishAsync( TPublishOptions options, diff --git a/src/Tableau.Migration/Api/Publishing/IFilePublisher.cs b/src/Tableau.Migration/Api/Publishing/IFilePublisher.cs index 6a65abc7..e61cc95e 100644 --- a/src/Tableau.Migration/Api/Publishing/IFilePublisher.cs +++ b/src/Tableau.Migration/Api/Publishing/IFilePublisher.cs @@ -32,7 +32,7 @@ public interface IFilePublisher /// Publishes the file with the specified options. /// /// The publish options - /// A cancellation token to obey. + /// The cancellation token to obey. Task> PublishAsync(TPublishOptions options, CancellationToken cancel); } } \ No newline at end of file diff --git a/src/Tableau.Migration/Api/Rest/Models/ITableauServerListResponse.cs b/src/Tableau.Migration/Api/Rest/Models/ITableauServerListResponse.cs index 3f70f533..e98f840c 100644 --- a/src/Tableau.Migration/Api/Rest/Models/ITableauServerListResponse.cs +++ b/src/Tableau.Migration/Api/Rest/Models/ITableauServerListResponse.cs @@ -21,10 +21,10 @@ namespace Tableau.Migration.Api.Rest.Models /// Interface representing REST API responses with multiple items. /// /// The response's item type. - public interface ITableauServerListResponse + public interface ITableauServerListResponse : ITableauServerResponse { /// - /// Gets the item for the response. + /// Gets the items for the response. /// TItems[] Items { get; set; } } diff --git a/src/Tableau.Migration/Api/Rest/Models/ITableauServerResponse.cs b/src/Tableau.Migration/Api/Rest/Models/ITableauServerResponse.cs index c037cf3f..15029f67 100644 --- a/src/Tableau.Migration/Api/Rest/Models/ITableauServerResponse.cs +++ b/src/Tableau.Migration/Api/Rest/Models/ITableauServerResponse.cs @@ -17,11 +17,22 @@ namespace Tableau.Migration.Api.Rest.Models { + /// + /// Interface representing REST API responses. + /// + public interface ITableauServerResponse + { + /// + /// Gets or sets the error for the response. + /// + Error? Error { get; set; } + } + /// /// Interface representing REST API responses with a single item. /// /// The response's item type. - public interface ITableauServerResponse + public interface ITableauServerResponse : ITableauServerResponse { /// /// Gets the item for the response. diff --git a/src/Tableau.Migration/Api/Rest/Models/IWithWorkbookType.cs b/src/Tableau.Migration/Api/Rest/Models/IWithWorkbookType.cs deleted file mode 100644 index 1cd83d65..00000000 --- a/src/Tableau.Migration/Api/Rest/Models/IWithWorkbookType.cs +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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. -// - -namespace Tableau.Migration.Api.Rest.Models -{ - /// - /// Interface for an object that has an owner user reference. - /// - public interface IWithWorkbookReferenceType - { - /// - /// Gets the owner for the response. - /// - IWorkbookReferenceType? Workbook { get; } - } -} diff --git a/src/Tableau.Migration/Api/Rest/Models/IWorkbookReferenceType.cs b/src/Tableau.Migration/Api/Rest/Models/IWorkbookReferenceType.cs deleted file mode 100644 index 8f6758aa..00000000 --- a/src/Tableau.Migration/Api/Rest/Models/IWorkbookReferenceType.cs +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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. -// - -namespace Tableau.Migration.Api.Rest.Models -{ - /// - /// Interface representing an XML element for the view of a content item. - /// - public interface IWorkbookReferenceType : IRestIdentifiable - { } -} diff --git a/src/Tableau.Migration/Api/Rest/Models/Requests/PermissionsAddRequest.cs b/src/Tableau.Migration/Api/Rest/Models/Requests/PermissionsAddRequest.cs index 97aec81e..eaaab491 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Requests/PermissionsAddRequest.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Requests/PermissionsAddRequest.cs @@ -15,7 +15,6 @@ // limitations under the License. // -using System.Xml; using System.Xml.Serialization; using Tableau.Migration.Api.Rest.Models.Types; using Tableau.Migration.Content.Permissions; diff --git a/src/Tableau.Migration/Api/Rest/Models/Responses/PermissionsResponse.cs b/src/Tableau.Migration/Api/Rest/Models/Responses/PermissionsResponse.cs index 2ffabab9..e5cbbe0d 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Responses/PermissionsResponse.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Responses/PermissionsResponse.cs @@ -16,7 +16,6 @@ // using System; -using System.Xml; using System.Xml.Serialization; using Tableau.Migration.Api.Rest.Models.Types; diff --git a/src/Tableau.Migration/Api/Rest/Models/Responses/TableauServerResponse.cs b/src/Tableau.Migration/Api/Rest/Models/Responses/TableauServerResponse.cs index 43c503e7..05abdd07 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Responses/TableauServerResponse.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Responses/TableauServerResponse.cs @@ -23,16 +23,14 @@ namespace Tableau.Migration.Api.Rest.Models.Responses /// /// Base class representing REST API responses. /// - public abstract class TableauServerResponse + public abstract class TableauServerResponse : ITableauServerResponse { /// /// Gets the XML type name for Tableau Server REST API responses, i.e. <tsResponse> /// internal const string XmlTypeName = "tsResponse"; - /// - /// Gets or sets the error for the response. - /// + /// [XmlElement("error")] public Error? Error { get; set; } diff --git a/src/Tableau.Migration/Api/Rest/Models/Responses/ViewResponse.cs b/src/Tableau.Migration/Api/Rest/Models/Responses/ViewResponse.cs index 04af2fb0..ce20070a 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Responses/ViewResponse.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Responses/ViewResponse.cs @@ -72,7 +72,7 @@ public class ViewType : IViewType [XmlElement("workbook")] WorkbookReferenceType? Workbook { get; set; } - IWorkbookReferenceType? IWithWorkbookReferenceType.Workbook => Workbook; + IRestIdentifiable? IWithWorkbookReferenceType.Workbook => Workbook; /// /// Gets or sets the tags for the response. @@ -120,7 +120,7 @@ public TagType(ITagType tag) /// Class representing a REST API workbook reference response. /// - public class WorkbookReferenceType : IWorkbookReferenceType + public class WorkbookReferenceType : IRestIdentifiable { /// [XmlAttribute("label")] diff --git a/src/Tableau.Migration/Api/Rest/Models/Types/ParentContentType.cs b/src/Tableau.Migration/Api/Rest/Models/Types/ParentContentType.cs index 095634c0..22b9f978 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Types/ParentContentType.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Types/ParentContentType.cs @@ -16,7 +16,6 @@ // using System; -using System.Xml; using System.Xml.Serialization; namespace Tableau.Migration.Api.Rest.Models.Types diff --git a/src/Tableau.Migration/Api/Rest/Models/Types/PermissionsType.cs b/src/Tableau.Migration/Api/Rest/Models/Types/PermissionsType.cs index aa3e0270..5a3bf5dd 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Types/PermissionsType.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Types/PermissionsType.cs @@ -16,7 +16,6 @@ // using System; -using System.Xml; using System.Xml.Serialization; namespace Tableau.Migration.Api.Rest.Models.Types diff --git a/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs b/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs index 2b485379..76148088 100644 --- a/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs +++ b/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs @@ -29,11 +29,13 @@ internal static class RestUrlPrefixes [typeof(IFlowsApiClient)] = Flows, [typeof(IGroupsApiClient)] = Groups, [typeof(IJobsApiClient)] = Jobs, + [typeof(ISchedulesApiClient)] = Schedules, [typeof(IProjectsApiClient)] = Projects, [typeof(ISitesApiClient)] = Sites, [typeof(IUsersApiClient)] = Users, [typeof(IViewsApiClient)] = Views, [typeof(IWorkbooksApiClient)] = Workbooks, + [typeof(ITasksApiClient)] = Tasks, } .ToImmutableDictionary(InheritedTypeComparer.Instance); @@ -48,6 +50,8 @@ internal static class RestUrlPrefixes public const string Users = "users"; public const string Views = "views"; public const string Workbooks = "workbooks"; + public const string Schedules = "schedules"; + public const string Tasks = "tasks"; public static string GetUrlPrefix() where TApiClient : IContentApiClient diff --git a/src/Tableau.Migration/Api/Search/BulkApiContentReferenceCache.cs b/src/Tableau.Migration/Api/Search/BulkApiContentReferenceCache.cs index 4393e56a..1338e89d 100644 --- a/src/Tableau.Migration/Api/Search/BulkApiContentReferenceCache.cs +++ b/src/Tableau.Migration/Api/Search/BulkApiContentReferenceCache.cs @@ -66,10 +66,16 @@ protected virtual void ItemLoaded(TContent item) { } /// /// Loads all content items from the API client. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// All content items. protected async ValueTask> LoadAllAsync(CancellationToken cancel) { + if (_apiListClient is null) + { + // Values will be cached by individual searches. + return Enumerable.Empty(); + } + var listResult = await _apiListClient.GetAllAsync(BatchSize, cancel).ConfigureAwait(false); if (!listResult.Success) diff --git a/src/Tableau.Migration/Api/ServerSessionProvider.cs b/src/Tableau.Migration/Api/ServerSessionProvider.cs index dc2a90c5..c610823b 100644 --- a/src/Tableau.Migration/Api/ServerSessionProvider.cs +++ b/src/Tableau.Migration/Api/ServerSessionProvider.cs @@ -27,7 +27,7 @@ internal sealed class ServerSessionProvider : IServerSessionProvider private readonly ITableauServerVersionProvider _versionProvider; private readonly IAuthenticationTokenProvider _tokenProvider; - internal async Task GetAuthenticationTokenAsync(CancellationToken cancel) + internal async Task GetAuthenticationTokenAsync(CancellationToken cancel) => await _tokenProvider.GetAsync(cancel).ConfigureAwait(false); /// @@ -42,6 +42,9 @@ internal sealed class ServerSessionProvider : IServerSessionProvider /// public Guid? UserId { get; private set; } + /// + public TableauInstanceType InstanceType { get; private set; } + public ServerSessionProvider( ITableauServerVersionProvider versionProvider, IAuthenticationTokenProvider tokenProvider) @@ -51,25 +54,39 @@ public ServerSessionProvider( } /// - public async Task SetCurrentUserAndSiteAsync(ISignInResult signInResult, CancellationToken cancel) - => await SetCurrentUserAndSiteAsync(signInResult.UserId, signInResult.SiteId, signInResult.SiteContentUrl, signInResult.Token, cancel).ConfigureAwait(false); + public async Task SetCurrentSessionAsync(ISignInResult signInResult, TableauInstanceType instanceType, CancellationToken cancel) + => await SetCurrentSessionAsync( + signInResult.UserId, + signInResult.SiteId, + signInResult.SiteContentUrl, + signInResult.Token, + instanceType, + cancel).ConfigureAwait(false); /// - public async Task SetCurrentUserAndSiteAsync(Guid userId, Guid siteId, string siteContentUrl, string authenticationToken, CancellationToken cancel) + public async Task SetCurrentSessionAsync( + Guid userId, + Guid siteId, + string siteContentUrl, + string authenticationToken, + TableauInstanceType instanceType, + CancellationToken cancel) { SiteId = siteId; SiteContentUrl = siteContentUrl; UserId = userId; + InstanceType = instanceType; await _tokenProvider.SetAsync(authenticationToken, cancel).ConfigureAwait(false); } /// - public async Task ClearCurrentUserAndSiteAsync(CancellationToken cancel) + public async Task ClearCurrentSessionAsync(CancellationToken cancel) { SiteId = null; SiteContentUrl = null; UserId = null; + InstanceType = TableauInstanceType.Unknown; await _tokenProvider.ClearAsync(cancel).ConfigureAwait(false); } diff --git a/src/Tableau.Migration/Api/Simulation/ITableauApiSimulatorFactory.cs b/src/Tableau.Migration/Api/Simulation/ITableauApiSimulatorFactory.cs index d177af41..be36e2ed 100644 --- a/src/Tableau.Migration/Api/Simulation/ITableauApiSimulatorFactory.cs +++ b/src/Tableau.Migration/Api/Simulation/ITableauApiSimulatorFactory.cs @@ -28,7 +28,8 @@ public interface ITableauApiSimulatorFactory /// Creates an API simulator for the given server URL, or retrieves the existing simulator. /// /// The base server URL to get or create the API simulator for. - /// The API simulator. - TableauApiSimulator GetOrCreate(Uri serverUrl); + /// Indicates whether the current Tableau Data is for Tableau Server (true) or Tableau Cloud (false). + /// /// The API simulator. + TableauApiSimulator GetOrCreate(Uri serverUrl, bool isTableauServer); } } diff --git a/src/Tableau.Migration/Api/Simulation/Rest/RestApiSimulator.cs b/src/Tableau.Migration/Api/Simulation/Rest/RestApiSimulator.cs index 189643c8..c5cfb743 100644 --- a/src/Tableau.Migration/Api/Simulation/Rest/RestApiSimulator.cs +++ b/src/Tableau.Migration/Api/Simulation/Rest/RestApiSimulator.cs @@ -20,6 +20,7 @@ using Tableau.Migration.Api.Rest.Models.Responses; using Tableau.Migration.Api.Simulation.Rest.Api; using Tableau.Migration.Api.Simulation.Rest.Net; +using Tableau.Migration.Api.Simulation.Rest.Net.Responses; using Tableau.Migration.Net.Simulation; using static Tableau.Migration.Api.Simulation.Rest.Net.Requests.RestUrlPatterns; @@ -50,6 +51,16 @@ public sealed class RestApiSimulator /// Gets the simulated job API methods. /// public JobsRestApiSimulator Jobs { get; } + + /// + /// Gets the simulated schedule API methods. + /// + public SchedulesRestApiSimulator Schedules { get; } + + /// + /// Gets the simulated task API methods. + /// + public TasksRestApiSimulator Tasks { get; } /// /// Gets the simulated project API methods. @@ -91,6 +102,11 @@ public sealed class RestApiSimulator /// public MethodSimulator GetCurrentServerSession { get; } + /// + /// Gets the simulated site query API method. + /// + public MethodSimulator QuerySites { get; } + private static ServerSessionResponse.SessionType BuildCurrentSession(TableauData data) { var user = data.Users.Single(u => u.Id == data.SignIn!.User!.Id); @@ -132,6 +148,8 @@ public RestApiSimulator(TableauApiResponseSimulator simulator) DataSources = new(simulator); Groups = new(simulator); Jobs = new(simulator); + Schedules = new(simulator); + Tasks = new(simulator); Projects = new(simulator); Sites = new(simulator); Users = new(simulator); @@ -141,6 +159,9 @@ public RestApiSimulator(TableauApiResponseSimulator simulator) QueryServerInfo = simulator.SetupRestGet(RestApiUrl("serverinfo"), d => d.ServerInfo, requiresAuthentication: false); GetCurrentServerSession = simulator.SetupRestGet(RestApiUrl("sessions/current"), BuildCurrentSession); + QuerySites = simulator.SetupRestGet( + RestApiUrl($"sites"), + new RestGetSitesResponseBuilder(simulator.Data, simulator.Serializer)); } } } diff --git a/src/Tableau.Migration/Api/Simulation/TableauApiSimulator.cs b/src/Tableau.Migration/Api/Simulation/TableauApiSimulator.cs index d7d0b603..2fd87143 100644 --- a/src/Tableau.Migration/Api/Simulation/TableauApiSimulator.cs +++ b/src/Tableau.Migration/Api/Simulation/TableauApiSimulator.cs @@ -54,13 +54,19 @@ public sealed class TableauApiSimulator /// /// The base server URL. /// A serializer to use to produce responses. + /// Indicates whether the current Tableau Data is for Tableau Server (true) or Tableau Cloud (false). /// Default signed in user to user. If none is provided, the simulated server will have no users. /// The default domain of the site. - public TableauApiSimulator(Uri serverUrl, IHttpContentSerializer serializer, - UsersResponse.UserType? defaultSignedInUser = null, string defaultDomain = Constants.LocalDomain) + public TableauApiSimulator( + Uri serverUrl, + IHttpContentSerializer serializer, + bool isTableauServer, + UsersResponse.UserType? defaultSignedInUser = null, + string defaultDomain = Constants.LocalDomain) { ServerUrl = serverUrl; Data = new(defaultSignedInUser, defaultDomain); + Data.IsTableauServer = isTableauServer; ResponseSimulator = new TableauApiResponseSimulator(ServerUrl, Data, serializer); RestApi = new(ResponseSimulator); } diff --git a/src/Tableau.Migration/Api/Simulation/TableauApiSimulatorFactory.cs b/src/Tableau.Migration/Api/Simulation/TableauApiSimulatorFactory.cs index d94fca22..da167fd8 100644 --- a/src/Tableau.Migration/Api/Simulation/TableauApiSimulatorFactory.cs +++ b/src/Tableau.Migration/Api/Simulation/TableauApiSimulatorFactory.cs @@ -42,7 +42,7 @@ public TableauApiSimulatorFactory(ITableauApiSimulatorCollection simulators, IHt } /// - public TableauApiSimulator GetOrCreate(Uri serverUrl) + public TableauApiSimulator GetOrCreate(Uri serverUrl, bool isTableauServer) { var existing = _simulators.ForServer(serverUrl); if (existing is not null) @@ -59,7 +59,7 @@ public TableauApiSimulator GetOrCreate(Uri serverUrl) SiteRole = SiteRoles.SiteAdministratorCreator }; - var simulator = new TableauApiSimulator(serverUrl, _serializer, simulatorUser); + var simulator = new TableauApiSimulator(serverUrl, _serializer, isTableauServer, simulatorUser); _simulators.AddOrUpdate(simulator); return simulator; } diff --git a/src/Tableau.Migration/Api/Simulation/TableauData.cs b/src/Tableau.Migration/Api/Simulation/TableauData.cs index fbc07edc..b365f921 100644 --- a/src/Tableau.Migration/Api/Simulation/TableauData.cs +++ b/src/Tableau.Migration/Api/Simulation/TableauData.cs @@ -26,6 +26,8 @@ using Tableau.Migration.Content; using Tableau.Migration.Content.Permissions; using Tableau.Migration.Net.Rest; +using CloudResponse = Tableau.Migration.Api.Rest.Models.Responses.Cloud; +using ServerResponse = Tableau.Migration.Api.Rest.Models.Responses.Server; namespace Tableau.Migration.Api.Simulation { @@ -39,6 +41,11 @@ public sealed class TableauData /// public string DefaultDomain { get; set; } + /// + /// Gets the flag indicating whether the current Tableau Data is for Tableau Server (true) or Tableau Cloud (false). + /// + public bool IsTableauServer { get; set; } + /// /// Gets or sets the "All Users" group. /// @@ -88,6 +95,26 @@ public sealed class TableauData /// Gets or sets the jobs. /// public ConcurrentSet Jobs { get; set; } = new(); + + /// + /// Gets or sets the schedules. + /// + public ConcurrentSet Schedules { get; set; } = new(); + + /// + /// Gets or sets the schedules extract refresh tasks. + /// + public ConcurrentSet ScheduleExtractRefreshTasks { get; set; } = new(); + + /// + /// Gets or sets the Tableau Server extract refresh tasks. + /// + public ConcurrentSet ServerExtractRefreshTasks { get; set; } = new(); + + /// + /// Gets or sets the Tableau Cloud extract refresh tasks. + /// + public ConcurrentSet CloudExtractRefreshTasks { get; set; } = new(); /// /// Gets or sets the jobs. @@ -157,6 +184,11 @@ public sealed class TableauData /// public ConcurrentDictionary> UserGroups { get; set; } = new(); + /// + /// Gets the extract refresh tasks that users belong to, by ID. + /// + public ConcurrentDictionary> ScheduleExtracts { get; set; } = new(); + #endregion /// @@ -354,6 +386,39 @@ public void AddUserToGroup(UsersResponse.UserType user, GroupsResponse.GroupType AddUserToGroup(user.Id, group.Id); } + /// + /// Adds a schedule. + /// + /// The schedule to add. + public ServerResponse.ScheduleResponse.ScheduleType AddSchedule( + ServerResponse.ScheduleResponse.ScheduleType schedule) + { + if (ScheduleExtracts.ContainsKey(schedule.Id)) + { + return Schedules.Single(s => s.Id == schedule.Id); + } + + Schedules.Add(schedule); + ScheduleExtracts.TryAdd(schedule.Id, new()); + + return schedule; + } + + /// + /// Add a schedule extract refresh task to a schedule. + /// + /// The schedule extract refresh task. + /// The schedule. + public void AddExtractToSchedule( + ServerResponse.ScheduleExtractRefreshTasksResponse.ExtractType extract, + ServerResponse.ScheduleResponse.ScheduleType schedule) + { + schedule = AddSchedule(schedule); + ScheduleExtractRefreshTasks.Add(extract); + + ScheduleExtracts[schedule.Id].Add(extract.Id); + } + internal void UpdateFile(string sessionId, byte[] chunk) { Files.AddOrUpdate(sessionId, chunk, (_, __) => __.Concat(chunk)); diff --git a/src/Tableau.Migration/Api/SitesApiClient.cs b/src/Tableau.Migration/Api/SitesApiClient.cs index 786f39d4..b5e0b274 100644 --- a/src/Tableau.Migration/Api/SitesApiClient.cs +++ b/src/Tableau.Migration/Api/SitesApiClient.cs @@ -26,6 +26,9 @@ using Tableau.Migration.Api.Rest.Models.Responses; using Tableau.Migration.Api.Tags; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Net; using Tableau.Migration.Net.Rest; @@ -41,6 +44,8 @@ internal sealed class SitesApiClient : ContentApiClientBase, ISitesApiClient private readonly IServerSessionProvider _sessionProvider; private readonly IHttpContentSerializer _serializer; + private readonly ITasksApiClient _tasksApiClient; + public SitesApiClient( IRestRequestBuilderFactory restRequestBuilderFactory, IContentReferenceFinderFactory finderFactory, @@ -49,12 +54,14 @@ public SitesApiClient( ILoggerFactory loggerFactory, IGroupsApiClient groupsApiClient, IJobsApiClient jobsApiClient, + ISchedulesApiClient schedulesApiClient, IProjectsApiClient projectsApiClient, IUsersApiClient usersApiClient, IDataSourcesApiClient dataSourcesApiClient, IWorkbooksApiClient workbooksApiClient, IViewsApiClient viewsApiClient, IFlowsApiClient flowsApiClient, + ITasksApiClient tasksApiClient, ISharedResourcesLocalizer sharedResourcesLocalizer) : base(restRequestBuilderFactory, finderFactory, loggerFactory, sharedResourcesLocalizer) { @@ -63,12 +70,15 @@ public SitesApiClient( Groups = groupsApiClient; Jobs = jobsApiClient; + Schedules = schedulesApiClient; Projects = projectsApiClient; Users = usersApiClient; DataSources = dataSourcesApiClient; Workbooks = workbooksApiClient; Views = viewsApiClient; Flows = flowsApiClient; + + _tasksApiClient = tasksApiClient; } private static readonly ImmutableDictionary> _contentTypeAccessors = new Dictionary>(InheritedTypeComparer.Instance) @@ -79,7 +89,10 @@ public SitesApiClient( { typeof(IDataSource), client => client.DataSources }, { typeof(IWorkbook), client => client.Workbooks }, { typeof(IView), client => client.Views }, - { typeof(IFlow), client => client.Flows } + { typeof(IFlow), client => client.Flows }, + { typeof(IServerSchedule), client => client.Schedules }, + { typeof(IServerExtractRefreshTask), client => client.ServerTasks }, + { typeof(ICloudExtractRefreshTask), client => client.CloudTasks } } .ToImmutableDictionary(InheritedTypeComparer.Instance); @@ -97,6 +110,9 @@ public SitesApiClient( /// public IJobsApiClient Jobs { get; } + + /// + public ISchedulesApiClient Schedules { get; } /// public IProjectsApiClient Projects { get; } @@ -116,6 +132,14 @@ public SitesApiClient( /// public IFlowsApiClient Flows { get; } + /// + public IServerTasksApiClient ServerTasks + => ReturnForInstanceType(TableauInstanceType.Server, _sessionProvider.InstanceType, _tasksApiClient); + + /// + public ICloudTasksApiClient CloudTasks + => ReturnForInstanceType(TableauInstanceType.Cloud, _sessionProvider.InstanceType, _tasksApiClient); + /// public IReadApiClient? GetReadApiClient() where TContent : class @@ -206,7 +230,7 @@ public async Task> UpdateSiteAsync(ISiteSettingsUpdate update, Ca /// /// Signs out of Tableau Server. /// - /// The cancellation token + /// The cancellation token to obey. /// The sign out result. internal async Task SignOutAsync(CancellationToken cancel) { @@ -221,7 +245,7 @@ internal async Task SignOutAsync(CancellationToken cancel) .ToResultAsync(_serializer, SharedResourcesLocalizer, cancel) .ConfigureAwait(false); - await _sessionProvider.ClearCurrentUserAndSiteAsync(cancel).ConfigureAwait(false); + await _sessionProvider.ClearCurrentSessionAsync(cancel).ConfigureAwait(false); return signOutResult; } diff --git a/src/Tableau.Migration/Api/Tags/ITagsApiClient.cs b/src/Tableau.Migration/Api/Tags/ITagsApiClient.cs index 99e74026..37119dc9 100644 --- a/src/Tableau.Migration/Api/Tags/ITagsApiClient.cs +++ b/src/Tableau.Migration/Api/Tags/ITagsApiClient.cs @@ -34,7 +34,7 @@ public interface ITagsApiClient /// /// The ID of the content item. /// The tags to add. - /// A cancellation token to obey. + /// The cancellation token to obey. /// All tags on content item. Task>> AddTagsAsync(Guid contentItemId, IEnumerable tags, CancellationToken cancel); @@ -44,7 +44,7 @@ public interface ITagsApiClient /// /// The ID of the content item. /// The tags to remove. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Task RemoveTagsAsync(Guid contentItemId, IEnumerable tags, CancellationToken cancel); @@ -53,7 +53,7 @@ public interface ITagsApiClient /// /// The ID of the content ite. /// The tags to update to match. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Task UpdateTagsAsync(Guid contentItemId, IEnumerable tags, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Api/Tags/TagsApiClient.cs b/src/Tableau.Migration/Api/Tags/TagsApiClient.cs index 63c28f4e..af8cf3a1 100644 --- a/src/Tableau.Migration/Api/Tags/TagsApiClient.cs +++ b/src/Tableau.Migration/Api/Tags/TagsApiClient.cs @@ -84,18 +84,16 @@ public async Task RemoveTagsAsync(Guid contentItemId, IEnumerable return Result.Succeeded(); } - var aggregateResult = new List(); + var resultBuilder = new ResultBuilder(); - var deleteTasks = tags.Select(tag => RemoveTagAsync(contentItemId, tag, cancel)).ToList(); - - var deleteResults = await Task.WhenAll(deleteTasks).ConfigureAwait(false); - if (deleteResults is null) + foreach (var tag in tags) { - return Result.Failed(new Exception($"Failed to delete one or tags for {contentItemId}.")); + var deleteResult = await RemoveTagAsync(contentItemId, tag, cancel).ConfigureAwait(false); + + resultBuilder.Add(deleteResult); } - return new ResultBuilder() - .Add(deleteResults) + return resultBuilder .Build(); } diff --git a/src/Tableau.Migration/Api/UsersApiClient.cs b/src/Tableau.Migration/Api/UsersApiClient.cs index 17ab3d4d..7c5d9a24 100644 --- a/src/Tableau.Migration/Api/UsersApiClient.cs +++ b/src/Tableau.Migration/Api/UsersApiClient.cs @@ -22,7 +22,6 @@ using System.Linq; using System.Net.Http; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; diff --git a/src/Tableau.Migration/Api/ViewsApiClientFactory.cs b/src/Tableau.Migration/Api/ViewsApiClientFactory.cs index 3c83f2ac..77302aa1 100644 --- a/src/Tableau.Migration/Api/ViewsApiClientFactory.cs +++ b/src/Tableau.Migration/Api/ViewsApiClientFactory.cs @@ -50,7 +50,12 @@ public ViewsApiClientFactory( } public IViewsApiClient Create() - => new ViewsApiClient(_restRequestBuilderFactory, _permissionsClientFactory, _finderFactory, _loggerFactory, - _sharedResourcesLocalizer, _tagsClientFactory); + => new ViewsApiClient( + _restRequestBuilderFactory, + _permissionsClientFactory, + _finderFactory, + _loggerFactory, + _sharedResourcesLocalizer, + _tagsClientFactory); } } \ No newline at end of file diff --git a/src/Tableau.Migration/Api/WorkbooksApiClient.cs b/src/Tableau.Migration/Api/WorkbooksApiClient.cs index 032013d3..2eb3210c 100644 --- a/src/Tableau.Migration/Api/WorkbooksApiClient.cs +++ b/src/Tableau.Migration/Api/WorkbooksApiClient.cs @@ -29,7 +29,6 @@ using Tableau.Migration.Api.Tags; using Tableau.Migration.Content; using Tableau.Migration.Content.Files; -using Tableau.Migration.Content.Permissions; using Tableau.Migration.Content.Search; using Tableau.Migration.Net.Rest; using Tableau.Migration.Net.Rest.Sorting; diff --git a/src/Tableau.Migration/ComparerBase.cs b/src/Tableau.Migration/ComparerBase.cs index 38e6f242..29340b65 100644 --- a/src/Tableau.Migration/ComparerBase.cs +++ b/src/Tableau.Migration/ComparerBase.cs @@ -59,6 +59,36 @@ public int Compare(IEnumerable? x, IEnumerable? y) }); } + protected static int CompareValues(T x, T y, Func getValue, IComparer? comparer = null) + { + comparer ??= Comparer.Default; + + var xValue = getValue(x); + var yValue = getValue(y); + + return comparer.Compare(xValue, yValue); + } + + protected static int CompareValues(T x, T y, Func getValue, StringComparison comparison) + => CompareValues(x, y, getValue, StringComparer.FromComparison(comparison)); + + protected static int CompareValues(params Func[] comparisons) + { + Guard.AgainstNullOrEmpty(comparisons, nameof(comparisons)); + + var result = 0; + + foreach (var comparison in comparisons) + { + result = comparison(); + + if (result != 0) + return result; + } + + return result; + } + private static int Compare(TItem? x, TItem? y, Func compare) { if (x is null && y is null) diff --git a/src/Tableau.Migration/Constants.cs b/src/Tableau.Migration/Constants.cs index 8fb83f20..78eb2bb2 100644 --- a/src/Tableau.Migration/Constants.cs +++ b/src/Tableau.Migration/Constants.cs @@ -68,22 +68,24 @@ public static class Constants /// /// The name for the built-in admin insights project. - /// Admin Insight source: https://gitlab.tableausoftware.com/cloud-scale/admin-insights/genesis/blob/master/genesis/src/main/java/com/tableau/online/admindatasources/genesis/IConstants.java#L20 /// public const string AdminInsightsProjectName = "Admin Insights"; /// /// Alternate name for the built-in admin insights project. - /// /// Admin Insight source: https://gitlab.tableausoftware.com/cloud-scale/admin-insights/genesis/blob/master/genesis/src/main/java/com/tableau/online/admindatasources/genesis/IConstants.java#L20 /// public const string AdminInsightsTableauProjectName = "Admin Insights (Tableau)"; /// /// Alternate name for the built-in admin insights project. - /// /// Admin Insight source: https://gitlab.tableausoftware.com/cloud-scale/admin-insights/genesis/blob/master/genesis/src/main/java/com/tableau/online/admindatasources/genesis/IConstants.java#L20 /// public const string AdminInsightsTableauOnlineProjectName = "Admin Insights (Tableau Online)"; + /// + /// Schedules frequency format (reference). + /// + public const string FrequencyTimeFormat = "HH:mm:ss"; + /// /// The default text encoding. /// diff --git a/src/Tableau.Migration/Content/Files/IContentFileHandle.cs b/src/Tableau.Migration/Content/Files/IContentFileHandle.cs index 90362e96..949421b1 100644 --- a/src/Tableau.Migration/Content/Files/IContentFileHandle.cs +++ b/src/Tableau.Migration/Content/Files/IContentFileHandle.cs @@ -44,14 +44,14 @@ public interface IContentFileHandle : IAsyncDisposable /// /// Opens a stream to read from a file. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The stream to read from. Task OpenReadAsync(CancellationToken cancel); /// /// Opens a stream to write to a file. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The stream to write to. Task OpenWriteAsync(CancellationToken cancel); diff --git a/src/Tableau.Migration/Content/Files/IContentFileStore.cs b/src/Tableau.Migration/Content/Files/IContentFileStore.cs index 1564132d..a659c1c0 100644 --- a/src/Tableau.Migration/Content/Files/IContentFileStore.cs +++ b/src/Tableau.Migration/Content/Files/IContentFileStore.cs @@ -55,7 +55,7 @@ public interface IContentFileStore : IAsyncDisposable /// The relative path and file name to create a file for within the file store. /// The original file name external to the file store to preserve when publishing content items. /// The initial content to save the file with. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A handle to the newly created file. public async Task CreateAsync(string relativeStorePath, string originalFileName, Stream initialContent, CancellationToken cancel) @@ -78,7 +78,7 @@ public async Task CreateAsync(string relativeStorePath, stri /// The content item to resolve a relative file store path from. /// The original file name external to the file store to preserve when publishing content items. /// The initial content to save the file with. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A handle to the newly created file. public async Task CreateAsync(TContent contentItem, string originalFileName, Stream initialContent, CancellationToken cancel) @@ -98,7 +98,7 @@ public async Task CreateAsync(TContent contentItem /// Opens a stream to read from a file. /// /// The handle to the file to read from. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The stream to read from. Task OpenReadAsync(IContentFileHandle handle, CancellationToken cancel); @@ -106,7 +106,7 @@ public async Task CreateAsync(TContent contentItem /// Opens a stream to write to a file. /// /// The handle to the file to write to. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The stream to write to. Task OpenWriteAsync(IContentFileHandle handle, CancellationToken cancel); @@ -115,7 +115,7 @@ public async Task CreateAsync(TContent contentItem /// opening a new editor if necessary. /// /// The handle to the file to get the editor for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// /// True to consider the file a zip archive, /// false to consider the file an XML file, @@ -133,7 +133,7 @@ public async Task CreateAsync(TContent contentItem /// Changes will be flushed before closing. /// /// The handle to the file to close the editor for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A task to await. Task CloseTableauFileEditorAsync(IContentFileHandle handle, CancellationToken cancel); @@ -141,7 +141,7 @@ public async Task CreateAsync(TContent contentItem /// Deletes a file managed by the file store. /// /// The handle to the file to delete. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A task to await. Task DeleteAsync(IContentFileHandle handle, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Content/Files/ITableauFileXmlStream.cs b/src/Tableau.Migration/Content/Files/ITableauFileXmlStream.cs index 9c391e18..afddb71e 100644 --- a/src/Tableau.Migration/Content/Files/ITableauFileXmlStream.cs +++ b/src/Tableau.Migration/Content/Files/ITableauFileXmlStream.cs @@ -38,7 +38,7 @@ public interface ITableauFileXmlStream : IAsyncDisposable /// parsing the file if necessary. /// Changes to the XML will be automatically saved before publishing. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The XML document. Task GetXmlAsync(CancellationToken cancel); } diff --git a/src/Tableau.Migration/Content/Search/CachedContentReferenceFinder.cs b/src/Tableau.Migration/Content/Search/CachedContentReferenceFinder.cs index b3440363..7a861b9e 100644 --- a/src/Tableau.Migration/Content/Search/CachedContentReferenceFinder.cs +++ b/src/Tableau.Migration/Content/Search/CachedContentReferenceFinder.cs @@ -26,22 +26,15 @@ namespace Tableau.Migration.Content.Search /// a to find content references. /// /// The content type. - public class CachedContentReferenceFinder : IContentReferenceFinder + /// + /// Creates a new object. + /// + /// The content reference cache. + public class CachedContentReferenceFinder(IContentReferenceCache cache) : IContentReferenceFinder where TContent : IContentReference { - private readonly IContentReferenceCache _cache; - - /// - /// Creates a new object. - /// - /// The content reference cache. - public CachedContentReferenceFinder(IContentReferenceCache cache) - { - _cache = cache; - } - /// public async Task FindByIdAsync(Guid id, CancellationToken cancel) - => await _cache.ForIdAsync(id, cancel).ConfigureAwait(false); + => await cache.ForIdAsync(id, cancel).ConfigureAwait(false); } } diff --git a/src/Tableau.Migration/Content/Search/ContentReferenceCacheBase.cs b/src/Tableau.Migration/Content/Search/ContentReferenceCacheBase.cs index 1d9584dd..aab77caf 100644 --- a/src/Tableau.Migration/Content/Search/ContentReferenceCacheBase.cs +++ b/src/Tableau.Migration/Content/Search/ContentReferenceCacheBase.cs @@ -42,7 +42,7 @@ public abstract class ContentReferenceCacheBase : IContentReferenceCache /// Searches for content at the given location, possibly returning more locations to opportunistically cache. /// /// The primary location to search for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The content references to cache. protected abstract ValueTask> SearchAsync(ContentLocation searchLocation, CancellationToken cancel); @@ -50,7 +50,7 @@ public abstract class ContentReferenceCacheBase : IContentReferenceCache /// Searches for content at the given ID, possibly returning more references to opportunistically cache. /// /// The primary ID to search for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The content references to cache. protected abstract ValueTask> SearchAsync(Guid searchId, CancellationToken cancel); @@ -58,7 +58,7 @@ public abstract class ContentReferenceCacheBase : IContentReferenceCache /// Searches for content at the given location. /// /// The primary location to search for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The content reference to cache, or null. protected virtual Task IndividualSearchAsync(ContentLocation searchLocation, CancellationToken cancel) => Task.FromResult(null); @@ -67,7 +67,7 @@ public abstract class ContentReferenceCacheBase : IContentReferenceCache /// Searches for content at the given ID. /// /// The primary ID to search for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The content reference to cache, or null. protected virtual Task IndividualSearchAsync(Guid searchId, CancellationToken cancel) => Task.FromResult(null); diff --git a/src/Tableau.Migration/Content/Search/IContentReferenceCache.cs b/src/Tableau.Migration/Content/Search/IContentReferenceCache.cs index a874a453..f27fe5dc 100644 --- a/src/Tableau.Migration/Content/Search/IContentReferenceCache.cs +++ b/src/Tableau.Migration/Content/Search/IContentReferenceCache.cs @@ -31,7 +31,7 @@ public interface IContentReferenceCache /// Finds the content reference item for a given endpoint location. /// /// The location. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The content reference, or null if no item was found. Task ForLocationAsync(ContentLocation location, CancellationToken cancel); @@ -39,7 +39,7 @@ public interface IContentReferenceCache /// Finds the content reference item for a given endpoint ID. /// /// The ID. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The content reference, or null if no item was found. Task ForIdAsync(Guid id, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Content/Search/IContentReferenceFinder.cs b/src/Tableau.Migration/Content/Search/IContentReferenceFinder.cs index 9fcbb8e0..da3388c5 100644 --- a/src/Tableau.Migration/Content/Search/IContentReferenceFinder.cs +++ b/src/Tableau.Migration/Content/Search/IContentReferenceFinder.cs @@ -23,18 +23,25 @@ namespace Tableau.Migration.Content.Search { /// /// Interface for an object that can find s - /// for a given content type and search criteria. + /// for given search criteria. /// - /// The content type. - public interface IContentReferenceFinder - where TContent : IContentReference + public interface IContentReferenceFinder { /// /// Finds the content reference by its unique identifier. /// /// The unique identifier. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The found content reference, or null if no content reference was found. Task FindByIdAsync(Guid id, CancellationToken cancel); } + + /// + /// Interface for an object that can find s + /// for a given content type and search criteria. + /// + /// The content type. + public interface IContentReferenceFinder : IContentReferenceFinder + where TContent : IContentReference + { } } diff --git a/src/Tableau.Migration/Content/Search/IContentReferenceFinderFactory.cs b/src/Tableau.Migration/Content/Search/IContentReferenceFinderFactory.cs index 6f4a227d..3ae72a90 100644 --- a/src/Tableau.Migration/Content/Search/IContentReferenceFinderFactory.cs +++ b/src/Tableau.Migration/Content/Search/IContentReferenceFinderFactory.cs @@ -15,6 +15,9 @@ // limitations under the License. // +using System; +using Tableau.Migration.Content.Schedules; + namespace Tableau.Migration.Content.Search { /// @@ -30,5 +33,21 @@ public interface IContentReferenceFinderFactory /// The content reference finder. IContentReferenceFinder ForContentType() where TContent : class, IContentReference; + + /// + /// Gets or creates a content reference finder for a given extract refresh content type. + /// + /// The extract refresh content type + /// The content reference finder. + public IContentReferenceFinder ForExtractRefreshContent(ExtractRefreshContentType contentType) + { + if (contentType is ExtractRefreshContentType.DataSource) + return ForContentType(); + + if (contentType is ExtractRefreshContentType.Workbook) + return ForContentType(); + + throw new NotSupportedException($"Content type {contentType} is not supported."); + } } } diff --git a/src/Tableau.Migration/Engine/Actions/IMigrationAction.cs b/src/Tableau.Migration/Engine/Actions/IMigrationAction.cs index 5740f5c8..f84b0939 100644 --- a/src/Tableau.Migration/Engine/Actions/IMigrationAction.cs +++ b/src/Tableau.Migration/Engine/Actions/IMigrationAction.cs @@ -28,7 +28,7 @@ public interface IMigrationAction /// /// Executes the migration action. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// An awaitable task for the overall action result. Task ExecuteAsync(CancellationToken cancel); } diff --git a/src/Tableau.Migration/Engine/Endpoints/IDestinationEndpoint.cs b/src/Tableau.Migration/Engine/Endpoints/IDestinationEndpoint.cs index cf883592..4ae97188 100644 --- a/src/Tableau.Migration/Engine/Endpoints/IDestinationEndpoint.cs +++ b/src/Tableau.Migration/Engine/Endpoints/IDestinationEndpoint.cs @@ -37,7 +37,7 @@ public interface IDestinationEndpoint : IMigrationEndpoint /// The content type suitable for publishing. /// The publish result type. /// The content item to publish. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the publishing with a content reference of the newly published item. Task> PublishAsync(TPublish publishItem, CancellationToken cancel) where TPublishResult : class, IContentReference; @@ -47,7 +47,7 @@ Task> PublishAsync(TPublish pu /// /// The content type suitable for publishing. /// The content items to publish. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the publishing. Task PublishBatchAsync(IEnumerable publishItems, CancellationToken cancel); @@ -56,7 +56,7 @@ Task> PublishAsync(TPublish pu /// /// The content type. /// The content item to get permissions for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the permissions operation. Task> GetPermissionsAsync(IContentReference contentItem, CancellationToken cancel) where TContent : IPermissionsContent; @@ -66,7 +66,7 @@ Task> GetPermissionsAsync(IContentReference cont /// /// The content type. /// The content item to get permissions for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the permissions operation. Task> GetPermissionsAsync(Type type, IContentReference contentItem, CancellationToken cancel); @@ -98,7 +98,7 @@ Task> UpdatePermissionsAsync(Type type, IContentReference /// The content type. /// The content item to update tags for. /// The tags to apply. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the tag update operation. Task UpdateTagsAsync(IContentReference contentItem, IEnumerable tags, CancellationToken cancel) where TContent : IWithTags; @@ -109,7 +109,7 @@ Task UpdateTagsAsync(IContentReference contentItem, IEnumerab /// The content type. /// The content item to update ownership for. /// The new owner. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the owner update operation. Task UpdateOwnerAsync(IContentReference contentItem, IContentReference owner, CancellationToken cancel) where TContent : IWithOwner; diff --git a/src/Tableau.Migration/Engine/Endpoints/IMigrationEndpoint.cs b/src/Tableau.Migration/Engine/Endpoints/IMigrationEndpoint.cs index ffa8844d..c1aae0f7 100644 --- a/src/Tableau.Migration/Engine/Endpoints/IMigrationEndpoint.cs +++ b/src/Tableau.Migration/Engine/Endpoints/IMigrationEndpoint.cs @@ -31,7 +31,7 @@ public interface IMigrationEndpoint : IAsyncDisposable /// /// Performs pre-migration initialization. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// An awaitable task with the initialization result. Task InitializeAsync(CancellationToken cancel); @@ -46,7 +46,7 @@ public interface IMigrationEndpoint : IAsyncDisposable /// /// Gets the current server session information. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// An awaitable task with the server session result. Task> GetSessionAsync(CancellationToken cancel); } diff --git a/src/Tableau.Migration/Engine/Endpoints/ISourceEndpoint.cs b/src/Tableau.Migration/Engine/Endpoints/ISourceEndpoint.cs index b33ee369..f237aa60 100644 --- a/src/Tableau.Migration/Engine/Endpoints/ISourceEndpoint.cs +++ b/src/Tableau.Migration/Engine/Endpoints/ISourceEndpoint.cs @@ -36,7 +36,7 @@ public interface ISourceEndpoint : IMigrationEndpoint /// The content type. /// The publish type. /// The content item to pull. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the pull operation with the item to publish. Task> PullAsync(TContent contentItem, CancellationToken cancel) where TPublish : class; @@ -46,7 +46,7 @@ Task> PullAsync(TContent contentItem, Canc /// /// The content type. /// The content item to get permissions for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the permissions operation. Task> GetPermissionsAsync(IContentReference contentItem, CancellationToken cancel) where TContent : IPermissionsContent; @@ -56,7 +56,7 @@ Task> GetPermissionsAsync(IContentReference cont /// /// The content type. /// The content item to get permissions for. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the permissions operation. Task> GetPermissionsAsync(Type type, IContentReference contentItem, CancellationToken cancel); diff --git a/src/Tableau.Migration/Engine/Endpoints/Search/ILockedProjectCache.cs b/src/Tableau.Migration/Engine/Endpoints/Search/ILockedProjectCache.cs index f5398dc8..fa7573ac 100644 --- a/src/Tableau.Migration/Engine/Endpoints/Search/ILockedProjectCache.cs +++ b/src/Tableau.Migration/Engine/Endpoints/Search/ILockedProjectCache.cs @@ -32,7 +32,7 @@ public interface ILockedProjectCache /// Finds whether a project is locked. /// /// The ID of the project. - /// A cancellation token to obey. + /// The cancellation token to obey. /// /// Whether or not to consider as locked. /// Except for narrow special cases this is true. diff --git a/src/Tableau.Migration/Engine/Endpoints/TableauApiDestinationEndpoint.cs b/src/Tableau.Migration/Engine/Endpoints/TableauApiDestinationEndpoint.cs index f55a3fe6..21ae3492 100644 --- a/src/Tableau.Migration/Engine/Endpoints/TableauApiDestinationEndpoint.cs +++ b/src/Tableau.Migration/Engine/Endpoints/TableauApiDestinationEndpoint.cs @@ -30,7 +30,7 @@ namespace Tableau.Migration.Engine.Endpoints { /// - /// implementation that uses Tableau Server/Cloud APIs. + /// implementation that uses Tableau Server/Cloud APIs. /// public class TableauApiDestinationEndpoint : TableauApiEndpointBase, IDestinationApiEndpoint { diff --git a/src/Tableau.Migration/Engine/Hooks/Filters/ContentFilterBase.cs b/src/Tableau.Migration/Engine/Hooks/Filters/ContentFilterBase.cs index f3f72725..eda24dac 100644 --- a/src/Tableau.Migration/Engine/Hooks/Filters/ContentFilterBase.cs +++ b/src/Tableau.Migration/Engine/Hooks/Filters/ContentFilterBase.cs @@ -19,7 +19,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Tableau.Migration.Resources; @@ -32,8 +31,6 @@ namespace Tableau.Migration.Engine.Hooks.Filters public abstract class ContentFilterBase : IContentFilter where TContent : IContentReference { - private readonly ISharedResourcesLocalizer? _localizer; - private readonly ILogger>? _logger; private readonly string _typeName; /// @@ -43,17 +40,27 @@ public abstract class ContentFilterBase : IContentFilter /// Default logger. public ContentFilterBase( ISharedResourcesLocalizer? localizer, - ILogger>? logger - ) + ILogger>? logger) { - _localizer = localizer; - _logger = logger; + Localizer = localizer; + Logger = logger; _typeName = GetType().Name; } + /// + /// The string localizer. + /// + protected ISharedResourcesLocalizer? Localizer { get; } + + /// + /// Default logger. + /// + protected ILogger>? Logger { get; } + /// - public Task>?> ExecuteAsync(IEnumerable> unfilteredItems, - CancellationToken cancel) + public Task>?> ExecuteAsync( + IEnumerable> unfilteredItems, + CancellationToken cancel) { var result = unfilteredItems; @@ -63,7 +70,7 @@ public ContentFilterBase( result = unfilteredItems.Where(ShouldMigrate); // Log the filtered items if requested - if ((_logger?.IsEnabled(LogLevel.Debug) ?? false) && _localizer is not null) + if (Logger is not null && Localizer is not null) { // Don't do the work if the logger is not enabled for this level var filteredItems = unfilteredItems.Except(result).ToList(); @@ -71,7 +78,10 @@ public ContentFilterBase( { foreach (var filteredItem in filteredItems) { - _logger?.LogDebug(_localizer.GetString(SharedResourceKeys.ContentFilterBaseDebugMessage), _typeName, filteredItem.SourceItem.ToStringForLog()); + Logger.LogDebug( + Localizer[SharedResourceKeys.ContentFilterBaseDebugMessage], + _typeName, + filteredItem.SourceItem.ToStringForLog()); } } } diff --git a/src/Tableau.Migration/Engine/Hooks/Filters/Default/UserSiteRoleSupportUserFilter.cs b/src/Tableau.Migration/Engine/Hooks/Filters/Default/UserSiteRoleSupportUserFilter.cs index f8189819..52622343 100644 --- a/src/Tableau.Migration/Engine/Hooks/Filters/Default/UserSiteRoleSupportUserFilter.cs +++ b/src/Tableau.Migration/Engine/Hooks/Filters/Default/UserSiteRoleSupportUserFilter.cs @@ -16,7 +16,6 @@ // using Microsoft.Extensions.Logging; -using Polly; using Tableau.Migration.Api.Rest.Models; using Tableau.Migration.Content; using Tableau.Migration.Resources; diff --git a/src/Tableau.Migration/Engine/Hooks/Filters/IContentFilterRunner.cs b/src/Tableau.Migration/Engine/Hooks/Filters/IContentFilterRunner.cs index 7c10f0ed..272bc317 100644 --- a/src/Tableau.Migration/Engine/Hooks/Filters/IContentFilterRunner.cs +++ b/src/Tableau.Migration/Engine/Hooks/Filters/IContentFilterRunner.cs @@ -31,7 +31,7 @@ public interface IContentFilterRunner /// /// The content type. /// The items to filter. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A lazy-evaluated collection of filterered items. Task>> ExecuteAsync(IEnumerable> itemsToFilter, CancellationToken cancel) where TContent : IContentReference; diff --git a/src/Tableau.Migration/Engine/Hooks/IMigrationHook.cs b/src/Tableau.Migration/Engine/Hooks/IMigrationHook.cs index aab5f911..ee18d870 100644 --- a/src/Tableau.Migration/Engine/Hooks/IMigrationHook.cs +++ b/src/Tableau.Migration/Engine/Hooks/IMigrationHook.cs @@ -30,7 +30,7 @@ public interface IMigrationHook /// Executes a hook callback. /// /// The input context from the migration engine or previous hook. - /// A cancellation token to obey. + /// The cancellation token to obey. /// /// A task to await containing the context, /// potentially modified to pass on to the next hook or migration engine, diff --git a/src/Tableau.Migration/Engine/Hooks/Mappings/ContentMappingBase.cs b/src/Tableau.Migration/Engine/Hooks/Mappings/ContentMappingBase.cs index 079e51ab..3592d5e2 100644 --- a/src/Tableau.Migration/Engine/Hooks/Mappings/ContentMappingBase.cs +++ b/src/Tableau.Migration/Engine/Hooks/Mappings/ContentMappingBase.cs @@ -29,8 +29,6 @@ namespace Tableau.Migration.Engine.Hooks.Mappings public abstract class ContentMappingBase : IContentMapping where TContent : IContentReference { - private readonly ISharedResourcesLocalizer? _localizer; - private readonly ILogger>? _logger; private readonly string _typeName; /// @@ -42,19 +40,35 @@ public ContentMappingBase( ISharedResourcesLocalizer? localizer, ILogger>? logger) { - _localizer = localizer; - _logger = logger; - _typeName = this.GetType().Name; + Localizer = localizer; + Logger = logger; + _typeName = GetType().Name; } + /// + /// The string localizer. + /// + protected ISharedResourcesLocalizer? Localizer { get; } + + /// + /// Default logger. + /// + protected ILogger>? Logger { get; } + /// public async Task?> ExecuteAsync(ContentMappingContext ctx, CancellationToken cancel) { var ret = await MapAsync(ctx, cancel).ConfigureAwait(false); - if((_logger is not null) && (_localizer is not null)) - _logger.LogDebug(_localizer[(SharedResourceKeys.ContentMappingBaseDebugMessage)], _typeName, ctx.ContentItem.ToStringForLog(), ctx.MappedLocation); - + if (Logger is not null && Localizer is not null) + { + Logger.LogDebug( + Localizer[SharedResourceKeys.ContentMappingBaseDebugMessage], + _typeName, + ctx.ContentItem.ToStringForLog(), + ctx.MappedLocation); + } + return ret; } @@ -62,7 +76,7 @@ public ContentMappingBase( /// Executes the mapping. /// /// The input context from the migration engine or previous hook. - /// A cancellation token to obey. + /// The cancellation token to obey. /// /// A task to await containing the context, /// potentially modified to pass on to the next hook or migration engine, diff --git a/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMapping.cs b/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMapping.cs index e0ae39a1..ba93f179 100644 --- a/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMapping.cs +++ b/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMapping.cs @@ -44,7 +44,7 @@ public AuthenticationTypeDomainMapping(IMigrationPlanOptionsProvider /// The type. /// The mapping context. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The mapped context. protected override Task?> ExecuteAsync(ContentMappingContext context, CancellationToken cancel) { diff --git a/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMappingBase.cs b/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMappingBase.cs index c260f435..1e90d5c1 100644 --- a/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMappingBase.cs +++ b/src/Tableau.Migration/Engine/Hooks/Mappings/Default/AuthenticationTypeDomainMappingBase.cs @@ -32,7 +32,7 @@ public abstract class AuthenticationTypeDomainMappingBase /// /// The type. /// The mapping context. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The mapped context. protected abstract Task?> ExecuteAsync(ContentMappingContext context, CancellationToken cancel) where T : IUsernameContent; diff --git a/src/Tableau.Migration/Engine/Hooks/Mappings/Default/CallbackAuthenticationTypeDomainMapping.cs b/src/Tableau.Migration/Engine/Hooks/Mappings/Default/CallbackAuthenticationTypeDomainMapping.cs index 5d260465..00726798 100644 --- a/src/Tableau.Migration/Engine/Hooks/Mappings/Default/CallbackAuthenticationTypeDomainMapping.cs +++ b/src/Tableau.Migration/Engine/Hooks/Mappings/Default/CallbackAuthenticationTypeDomainMapping.cs @@ -44,7 +44,7 @@ public CallbackAuthenticationTypeDomainMapping(Func /// The type. /// The mapping context. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The mapped context. protected override async Task?> ExecuteAsync(ContentMappingContext context, CancellationToken cancel) { diff --git a/src/Tableau.Migration/Engine/Hooks/Mappings/IContentMappingRunner.cs b/src/Tableau.Migration/Engine/Hooks/Mappings/IContentMappingRunner.cs index 254e198c..84b51686 100644 --- a/src/Tableau.Migration/Engine/Hooks/Mappings/IContentMappingRunner.cs +++ b/src/Tableau.Migration/Engine/Hooks/Mappings/IContentMappingRunner.cs @@ -30,7 +30,7 @@ public interface IContentMappingRunner /// /// The content type. /// The mapping context. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result context with the mapped content location. Task> ExecuteAsync(ContentMappingContext context, CancellationToken cancel) where TContent : IContentReference; diff --git a/src/Tableau.Migration/Engine/Hooks/MigrationHookBuilder.cs b/src/Tableau.Migration/Engine/Hooks/MigrationHookBuilder.cs index 771056aa..781517d2 100644 --- a/src/Tableau.Migration/Engine/Hooks/MigrationHookBuilder.cs +++ b/src/Tableau.Migration/Engine/Hooks/MigrationHookBuilder.cs @@ -54,7 +54,7 @@ public IMigrationHookBuilder Clear() } /// - public IMigrationHookBuilder Add(Type genericHookType, IEnumerable contentTypes) + public virtual IMigrationHookBuilder Add(Type genericHookType, IEnumerable contentTypes) { if (!genericHookType.IsGenericTypeDefinition) throw new ArgumentException($"Type {genericHookType.FullName} is not a generic type definition."); @@ -75,14 +75,14 @@ object hookFactory(IServiceProvider services) } /// - public IMigrationHookBuilder Add(THook hook) + public virtual IMigrationHookBuilder Add(THook hook) where THook : notnull { return Add(typeof(THook), s => hook); } /// - public IMigrationHookBuilder Add(Func? hookFactory = null) + public virtual IMigrationHookBuilder Add(Func? hookFactory = null) where THook : notnull { hookFactory ??= services => @@ -93,7 +93,7 @@ public IMigrationHookBuilder Add(Func? hookFacto } /// - public IMigrationHookBuilder Add(Func> callback) + public virtual IMigrationHookBuilder Add(Func> callback) where THook : IMigrationHook => Add(typeof(THook), s => new CallbackHookWrapper(callback)); diff --git a/src/Tableau.Migration/Engine/Hooks/PostPublish/Default/PermissionPostPublishHookBase.cs b/src/Tableau.Migration/Engine/Hooks/PostPublish/Default/PermissionPostPublishHookBase.cs index 9e41fc20..c7a342e3 100644 --- a/src/Tableau.Migration/Engine/Hooks/PostPublish/Default/PermissionPostPublishHookBase.cs +++ b/src/Tableau.Migration/Engine/Hooks/PostPublish/Default/PermissionPostPublishHookBase.cs @@ -66,7 +66,7 @@ public PermissionPostPublishHookBase(IMigration migration) /// Finds whether or not the parent/containing project is locked. /// /// The post publish context. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Whether or not the parent project is locked. protected async Task ParentProjectLockedAsync( ContentItemPostPublishContext ctx, diff --git a/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBase.cs b/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBase.cs index cb04e132..668a46ad 100644 --- a/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBase.cs +++ b/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBase.cs @@ -29,8 +29,6 @@ namespace Tableau.Migration.Engine.Hooks.Transformers public abstract class ContentTransformerBase : IContentTransformer where TPublish : IContentReference { - private readonly ISharedResourcesLocalizer? _localizer; - private readonly ILogger>? _logger; private readonly string _typeName; /// @@ -39,21 +37,36 @@ public abstract class ContentTransformerBase : IContentTransformerA string localizer. /// Default logger. public ContentTransformerBase( - ISharedResourcesLocalizer? localizer, - ILogger>? logger) + ISharedResourcesLocalizer localizer, + ILogger> logger) { - _localizer = localizer; - _logger = logger; - _typeName = this.GetType().Name; + Localizer = localizer; + Logger = logger; + _typeName = GetType().Name; } + /// + /// The string localizer. + /// + protected ISharedResourcesLocalizer Localizer { get; } + + /// + /// Default logger. + /// + protected ILogger> Logger { get; } + /// public async Task ExecuteAsync(TPublish itemToTransform, CancellationToken cancel) { var ret = await TransformAsync(itemToTransform, cancel).ConfigureAwait(false); - if ((_logger is not null) && (_localizer is not null)) - _logger.LogDebug(_localizer[SharedResourceKeys.ContentTransformerBaseDebugMessage], _typeName, itemToTransform.ToStringForLog()); + if (Logger is not null && Localizer is not null) + { + Logger.LogDebug( + Localizer[SharedResourceKeys.ContentTransformerBaseDebugMessage], + _typeName, + itemToTransform.ToStringForLog()); + } return ret; } @@ -62,7 +75,7 @@ public ContentTransformerBase( /// Executes the transformation. /// /// The input context from the migration engine or previous hook. - /// A cancellation token to obey. + /// The cancellation token to obey. /// /// A task to await containing the context, /// potentially modified to pass on to the next hook or migration engine, diff --git a/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBuilder.cs b/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBuilder.cs index 66493ca7..dc008afc 100644 --- a/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBuilder.cs +++ b/src/Tableau.Migration/Engine/Hooks/Transformers/ContentTransformerBuilder.cs @@ -54,7 +54,7 @@ public virtual IContentTransformerBuilder Clear() } /// - public IContentTransformerBuilder Add(Type genericTransformerType, IEnumerable contentTypes) + public virtual IContentTransformerBuilder Add(Type genericTransformerType, IEnumerable contentTypes) { if (!genericTransformerType.IsGenericTypeDefinition) throw new ArgumentException($"Type {genericTransformerType.FullName} is not a generic type definition."); diff --git a/src/Tableau.Migration/Engine/Hooks/Transformers/Default/GroupUsersTransformer.cs b/src/Tableau.Migration/Engine/Hooks/Transformers/Default/GroupUsersTransformer.cs index 5898ece0..4870eeaf 100644 --- a/src/Tableau.Migration/Engine/Hooks/Transformers/Default/GroupUsersTransformer.cs +++ b/src/Tableau.Migration/Engine/Hooks/Transformers/Default/GroupUsersTransformer.cs @@ -30,9 +30,7 @@ namespace Tableau.Migration.Engine.Hooks.Transformers.Default public class GroupUsersTransformer : ContentTransformerBase { private readonly IDestinationContentReferenceFinder _userFinder; - private readonly ISharedResourcesLocalizer _localizer; - private readonly ILogger _logger; - + /// /// Creates a new object. /// @@ -45,8 +43,6 @@ public GroupUsersTransformer( ILogger logger) : base(localizer, logger) { _userFinder = destinationFinderFactory.ForDestinationContentType(); - _localizer = localizer; - _logger = logger; } /// @@ -66,7 +62,10 @@ public GroupUsersTransformer( } else { - _logger.LogWarning(_localizer[SharedResourceKeys.GroupUsersTransformerCannotAddUserWarning], sourceGroup.Name, user.User.Location); + Logger.LogWarning( + Localizer[SharedResourceKeys.GroupUsersTransformerCannotAddUserWarning], + sourceGroup.Name, + user.User.Location); } } return sourceGroup; diff --git a/src/Tableau.Migration/Engine/Hooks/Transformers/Default/MappedUserTransformer.cs b/src/Tableau.Migration/Engine/Hooks/Transformers/Default/MappedUserTransformer.cs index 21d29c27..7a60901a 100644 --- a/src/Tableau.Migration/Engine/Hooks/Transformers/Default/MappedUserTransformer.cs +++ b/src/Tableau.Migration/Engine/Hooks/Transformers/Default/MappedUserTransformer.cs @@ -20,7 +20,6 @@ using Microsoft.Extensions.Logging; using Tableau.Migration.Content; using Tableau.Migration.Engine.Endpoints.Search; -using Tableau.Migration.Engine.Pipelines; using Tableau.Migration.Resources; namespace Tableau.Migration.Engine.Hooks.Transformers.Default diff --git a/src/Tableau.Migration/Engine/Hooks/Transformers/IContentTransformerRunner.cs b/src/Tableau.Migration/Engine/Hooks/Transformers/IContentTransformerRunner.cs index f9a8eb5a..f274fffd 100644 --- a/src/Tableau.Migration/Engine/Hooks/Transformers/IContentTransformerRunner.cs +++ b/src/Tableau.Migration/Engine/Hooks/Transformers/IContentTransformerRunner.cs @@ -30,7 +30,7 @@ public interface IContentTransformerRunner /// /// The publishable content type. /// The items to transform. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The resulting transformed item. Task ExecuteAsync(TPublish itemToTransform, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Engine/Hooks/Transformers/IXmlContentTransformer.cs b/src/Tableau.Migration/Engine/Hooks/Transformers/IXmlContentTransformer.cs index db8277c8..0073faf2 100644 --- a/src/Tableau.Migration/Engine/Hooks/Transformers/IXmlContentTransformer.cs +++ b/src/Tableau.Migration/Engine/Hooks/Transformers/IXmlContentTransformer.cs @@ -45,7 +45,7 @@ public interface IXmlContentTransformer : IContentTransformer - /// A cancellation token to obey. + /// The cancellation token to obey. /// A task to await. Task TransformAsync(TPublish ctx, XDocument xml, CancellationToken cancel); diff --git a/src/Tableau.Migration/Engine/IServiceCollectionExtensions.cs b/src/Tableau.Migration/Engine/IServiceCollectionExtensions.cs index e7a05bb9..9681c633 100644 --- a/src/Tableau.Migration/Engine/IServiceCollectionExtensions.cs +++ b/src/Tableau.Migration/Engine/IServiceCollectionExtensions.cs @@ -86,6 +86,7 @@ internal static IServiceCollection AddMigrationEngine(this IServiceCollection se //Migrators //Register concrete types so that the easy way to get interface types is through IMigrationPipeline. services.AddScoped(typeof(EndpointContentItemPreparer<,>)); + services.AddScoped(typeof(ExtractRefreshTaskServerToCloudPreparer)); services.AddScoped(typeof(SourceContentItemPreparer<>)); services.AddScoped(typeof(BulkPublishContentBatchMigrator<>)); services.AddScoped(typeof(BulkPublishContentBatchMigrator<,>)); @@ -131,6 +132,9 @@ internal static IServiceCollection AddMigrationEngine(this IServiceCollection se services.AddScoped(); services.AddScoped(typeof(OwnershipTransformer<>)); services.AddScoped(); + services.AddScoped(typeof(CloudScheduleCompatibilityTransformer<>)); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -154,7 +158,7 @@ internal static IServiceCollection AddMigrationEngine(this IServiceCollection se * We look at IApiClientInputInitializer.IsInitialized to determine what scope we are in. */ var apiClientInput = s.GetRequiredService(); - if(apiClientInput.IsInitialized) + if (apiClientInput.IsInitialized) { return apiClientInput.FileStore; } diff --git a/src/Tableau.Migration/Engine/Manifest/IMigrationManifestEntryBuilder.cs b/src/Tableau.Migration/Engine/Manifest/IMigrationManifestEntryBuilder.cs index bee30fbc..6ec1f2b3 100644 --- a/src/Tableau.Migration/Engine/Manifest/IMigrationManifestEntryBuilder.cs +++ b/src/Tableau.Migration/Engine/Manifest/IMigrationManifestEntryBuilder.cs @@ -47,7 +47,7 @@ ImmutableArray CreateEntries(IReadOnlyCollectio /// The input content item type. /// The content items to map. /// An object to use to map entries. Supplied as a parameter to avoid DI circular references at plan initialization time. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The current entry builder, for fluent API usage. Task MapEntriesAsync(IEnumerable sourceContentItems, IContentMappingRunner mapper, CancellationToken cancel) where TItem : IContentReference; diff --git a/src/Tableau.Migration/Engine/MigrationPlanBuilder.cs b/src/Tableau.Migration/Engine/MigrationPlanBuilder.cs index f0070b4c..db04e96e 100644 --- a/src/Tableau.Migration/Engine/MigrationPlanBuilder.cs +++ b/src/Tableau.Migration/Engine/MigrationPlanBuilder.cs @@ -22,6 +22,8 @@ using System.Linq; using Tableau.Migration.Api.Simulation; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; using Tableau.Migration.Engine.Endpoints; using Tableau.Migration.Engine.Hooks; using Tableau.Migration.Engine.Hooks.Filters; @@ -121,6 +123,9 @@ public IMigrationPlanBuilder AppendDefaultExtensions() Transformers.Add(); Transformers.Add(typeof(OwnershipTransformer<>), GetPublishTypesByInterface()); Transformers.Add(); + Transformers.Add(); + Transformers.Add(); + Transformers.Add(typeof(CloudScheduleCompatibilityTransformer<>), GetPublishTypesByInterface>()); // Post-publish hooks. Hooks.Add(typeof(OwnerItemPostPublishHook<,>), GetPostPublishTypesByInterface()); @@ -144,7 +149,7 @@ public IMigrationPlanBuilder FromSourceTableauServer(Uri serverUrl, string siteC { if (createApiSimulator) { - _simulatorFactory.GetOrCreate(serverUrl); + _simulatorFactory.GetOrCreate(serverUrl, true); } return FromSource(new TableauApiEndpointConfiguration(new(serverUrl, siteContentUrl, accessTokenName, accessToken))); @@ -162,7 +167,7 @@ public IMigrationPlanBuilder ToDestinationTableauCloud(Uri podUrl, string siteCo { if (createApiSimulator) { - _simulatorFactory.GetOrCreate(podUrl); + _simulatorFactory.GetOrCreate(podUrl, false); } return ToDestination(new TableauApiEndpointConfiguration(new(podUrl, siteContentUrl, accessTokenName, accessToken))); diff --git a/src/Tableau.Migration/Engine/Migrators/Batch/ContentBatchMigratorBase.cs b/src/Tableau.Migration/Engine/Migrators/Batch/ContentBatchMigratorBase.cs index 1897b096..2a603035 100644 --- a/src/Tableau.Migration/Engine/Migrators/Batch/ContentBatchMigratorBase.cs +++ b/src/Tableau.Migration/Engine/Migrators/Batch/ContentBatchMigratorBase.cs @@ -56,7 +56,7 @@ public ContentBatchMigratorBase(IMigrationPipeline pipeline) /// /// The item being migrated. /// The prepared publish item. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the migration. protected abstract Task MigratePreparedItemAsync(ContentMigrationItem migrationItem, TPublish preparedItem, CancellationToken cancel); diff --git a/src/Tableau.Migration/Engine/Migrators/Batch/IContentBatchMigrator.cs b/src/Tableau.Migration/Engine/Migrators/Batch/IContentBatchMigrator.cs index 12c6a533..9471d036 100644 --- a/src/Tableau.Migration/Engine/Migrators/Batch/IContentBatchMigrator.cs +++ b/src/Tableau.Migration/Engine/Migrators/Batch/IContentBatchMigrator.cs @@ -32,7 +32,7 @@ public interface IContentBatchMigrator /// Migrates a batch of content items. /// /// The batch of content items to migrate. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the batch migration. Task> MigrateAsync(ImmutableArray> itemBatch, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Engine/Migrators/IContentMigrator.cs b/src/Tableau.Migration/Engine/Migrators/IContentMigrator.cs index ba0da564..93b56875 100644 --- a/src/Tableau.Migration/Engine/Migrators/IContentMigrator.cs +++ b/src/Tableau.Migration/Engine/Migrators/IContentMigrator.cs @@ -30,7 +30,7 @@ public interface IContentMigrator /// /// Migrates content for the given content type. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// A task to await. Task MigrateAsync(CancellationToken cancel); } diff --git a/src/Tableau.Migration/Engine/Pipelines/IMigrationPipelineRunner.cs b/src/Tableau.Migration/Engine/Pipelines/IMigrationPipelineRunner.cs index 87b82707..8a4f03f9 100644 --- a/src/Tableau.Migration/Engine/Pipelines/IMigrationPipelineRunner.cs +++ b/src/Tableau.Migration/Engine/Pipelines/IMigrationPipelineRunner.cs @@ -29,7 +29,7 @@ public interface IMigrationPipelineRunner /// Executes all pipeline actions. /// /// The pipeline to execute. - /// A cancellation token to obey. + /// The cancellation token to obey. /// An awaitable task for the overall pipeline execution result. Task ExecuteAsync(IMigrationPipeline pipeline, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineBase.cs b/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineBase.cs index 035810fc..9d02e2f1 100644 --- a/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineBase.cs +++ b/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineBase.cs @@ -20,6 +20,9 @@ using System.Collections.Immutable; using Microsoft.Extensions.DependencyInjection; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Engine.Actions; using Tableau.Migration.Engine.Endpoints.Search; @@ -104,6 +107,8 @@ public virtual IContentItemPreparer GetItemPreparer)Services.GetRequiredService>(); + case Type source when source == typeof(IServerExtractRefreshTask) && typeof(TPublish) == typeof(ICloudExtractRefreshTask): + return (IContentItemPreparer)Services.GetRequiredService(); default: return Services.GetRequiredService>(); } diff --git a/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineContentType.cs b/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineContentType.cs index a0d637d9..313d37ac 100644 --- a/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineContentType.cs +++ b/src/Tableau.Migration/Engine/Pipelines/MigrationPipelineContentType.cs @@ -18,7 +18,11 @@ using System; using System.Collections.Immutable; using System.Linq; +using System.Text; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Content.Schedules.Server; namespace Tableau.Migration.Engine.Pipelines { @@ -65,15 +69,10 @@ public record MigrationPipelineContentType(Type ContentType) public static readonly MigrationPipelineContentType Views = new MigrationPipelineContentType(); /// - /// Gets a collection of all s. + /// Gets the Server to Cloud extract refresh tasks . /// - public static readonly IImmutableList All = ImmutableArray.Create( - Users, - Groups, - Projects, - DataSources, - Workbooks - ); + public static readonly MigrationPipelineContentType ServerToCloudExtractRefreshTasks = new MigrationPipelineContentType() + .WithPublishType(); /// /// Gets the publish type. @@ -143,8 +142,25 @@ public MigrationPipelineContentType WithResultType() /// The config key string. public string GetConfigKey() { - var typeName = ContentType.Name; - return typeName.TrimStart('I'); + if (!ContentType.IsGenericType) + { + var typeName = ContentType.Name; + return typeName.TrimStart('I'); + } + + var convertedName = new StringBuilder() + .Append( + ContentType.Name + .TrimStart('I') + .TrimEnd('1') + .TrimEnd('`')); + + foreach (var arg in ContentType.GenericTypeArguments) + { + convertedName.Append($"_{arg.Name.TrimStart('I')}"); + } + + return convertedName.ToString(); } private static bool HasInterface(Type t, Type @interface) diff --git a/src/Tableau.Migration/Engine/Pipelines/ServerToCloudMigrationPipeline.cs b/src/Tableau.Migration/Engine/Pipelines/ServerToCloudMigrationPipeline.cs index 32b6b4ee..a6d207c7 100644 --- a/src/Tableau.Migration/Engine/Pipelines/ServerToCloudMigrationPipeline.cs +++ b/src/Tableau.Migration/Engine/Pipelines/ServerToCloudMigrationPipeline.cs @@ -21,6 +21,9 @@ using Microsoft.Extensions.DependencyInjection; using Tableau.Migration.Config; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Engine.Actions; using Tableau.Migration.Engine.Migrators.Batch; @@ -41,6 +44,7 @@ public class ServerToCloudMigrationPipeline : MigrationPipelineBase MigrationPipelineContentType.Projects, MigrationPipelineContentType.DataSources, MigrationPipelineContentType.Workbooks, + MigrationPipelineContentType.ServerToCloudExtractRefreshTasks ]; private readonly IConfigReader _configReader; @@ -72,6 +76,7 @@ protected override IEnumerable BuildPipeline() yield return CreateMigrateContentAction(); yield return CreateMigrateContentAction(); yield return CreateMigrateContentAction(); + yield return CreateMigrateContentAction(); } /// @@ -93,6 +98,8 @@ public override IContentBatchMigrator GetBatchMigrator() return Services.GetRequiredService>(); case Type worbook when worbook == typeof(IWorkbook): return Services.GetRequiredService>(); + case Type extractRefreshTask when extractRefreshTask == typeof(IServerExtractRefreshTask): + return Services.GetRequiredService>(); default: return base.GetBatchMigrator(); } diff --git a/src/Tableau.Migration/Engine/Preparation/ContentItemPreparerBase.cs b/src/Tableau.Migration/Engine/Preparation/ContentItemPreparerBase.cs index 56e6cadf..27de228e 100644 --- a/src/Tableau.Migration/Engine/Preparation/ContentItemPreparerBase.cs +++ b/src/Tableau.Migration/Engine/Preparation/ContentItemPreparerBase.cs @@ -53,7 +53,7 @@ public ContentItemPreparerBase( /// Pulls any additional information needed to prepare/publish a content item. /// /// The content item to use to pull additional information. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The item to use for publishing. protected abstract Task> PullAsync(ContentMigrationItem item, CancellationToken cancel); @@ -61,7 +61,7 @@ public ContentItemPreparerBase( /// Performs pre-publishing modifications on a publish item. /// /// The item intended for publishing to prepare. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The item to use for publishing. protected virtual async Task> TransformAsync(TPublish publishItem, CancellationToken cancel) { @@ -74,7 +74,7 @@ protected virtual async Task> TransformAsync(TPublish publishI /// /// The item to publish. /// The mapped destination location. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The result of the mapping application. protected virtual async Task ApplyMappingAsync(TPublish publishItem, ContentLocation mappedLocation, CancellationToken cancel) { @@ -134,7 +134,7 @@ protected virtual async Task ApplyMappingAsync(TPublish publishItem, ContentLoca /// Performs finalization tasks that occur after transformers, but before publishing. /// /// The item to publish. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A task to await. protected virtual async Task FinalizeAsync(TPublish publishItem, CancellationToken cancel) { diff --git a/src/Tableau.Migration/IContentReference.cs b/src/Tableau.Migration/IContentReference.cs index 08b256d7..cd3684d3 100644 --- a/src/Tableau.Migration/IContentReference.cs +++ b/src/Tableau.Migration/IContentReference.cs @@ -16,6 +16,7 @@ // using System; +using Tableau.Migration.Api.Rest; namespace Tableau.Migration { @@ -23,14 +24,8 @@ namespace Tableau.Migration /// Interface for an object that describes information on how to reference an item of content, /// for example through a Tableau API. /// - public interface IContentReference : IEquatable + public interface IContentReference : IEquatable, IRestIdentifiable { - /// - /// Gets the unique identifier of the content item, - /// corresponding to the LUID in the Tableau REST API. - /// - Guid Id { get; } - /// /// Get the site-unique "content URL" of the content item, /// or an empty string if the content type does not use a content URL. diff --git a/src/Tableau.Migration/IContentReferenceExtensions.cs b/src/Tableau.Migration/IContentReferenceExtensions.cs index ca51c5ee..29e3bfac 100644 --- a/src/Tableau.Migration/IContentReferenceExtensions.cs +++ b/src/Tableau.Migration/IContentReferenceExtensions.cs @@ -15,12 +15,6 @@ // limitations under the License. // -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Tableau.Migration { internal static class IContentReferenceExtensions diff --git a/src/Tableau.Migration/IMigrator.cs b/src/Tableau.Migration/IMigrator.cs index bcd1360d..41f404c5 100644 --- a/src/Tableau.Migration/IMigrator.cs +++ b/src/Tableau.Migration/IMigrator.cs @@ -29,7 +29,7 @@ public interface IMigrator /// Executes a migration asynchronously. /// /// The migration plan to execute. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the migration. Task ExecuteAsync(IMigrationPlan plan, CancellationToken cancel); @@ -38,7 +38,7 @@ public interface IMigrator /// /// The migration plan to execute. /// A manifest from a previous migration of the same plan to use to determine what progress has already been made. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The results of the migration. Task ExecuteAsync(IMigrationPlan plan, IMigrationManifest? previousManifest, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Interop/Hooks/Filters/ISyncContentFilter.cs b/src/Tableau.Migration/Interop/Hooks/Filters/ISyncContentFilter.cs deleted file mode 100644 index 65ef6b29..00000000 --- a/src/Tableau.Migration/Interop/Hooks/Filters/ISyncContentFilter.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Collections.Generic; -using Tableau.Migration.Engine; -using Tableau.Migration.Engine.Hooks.Filters; - -namespace Tableau.Migration.Interop.Hooks.Filters -{ - /// - /// Interface for an object that can synchronously filter content of a specific content type, to determine which content to migrate. - /// - /// - public interface ISyncContentFilter - : ISyncMigrationHook>>, IContentFilter - where TContent : IContentReference - { - /// - /// Executes a filter callback. - /// - /// The input context from the migration engine or previous filter. - /// - /// The context, - /// potentially modified to pass on to the next filter or migration engine, - /// or null to continue passing the same context as . - /// - new IEnumerable>? Execute(IEnumerable> ctx); - } -} diff --git a/src/Tableau.Migration/Interop/Hooks/Mappings/ISyncContentMapping.cs b/src/Tableau.Migration/Interop/Hooks/Mappings/ISyncContentMapping.cs deleted file mode 100644 index 7c4d86c1..00000000 --- a/src/Tableau.Migration/Interop/Hooks/Mappings/ISyncContentMapping.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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 Tableau.Migration.Engine.Hooks.Mappings; - -namespace Tableau.Migration.Interop.Hooks.Mappings -{ - /// - /// Interface for an object that can synchronously map content of a specific content type. - /// - /// - public interface ISyncContentMapping - : ISyncMigrationHook>, IContentMapping - where TContent : IContentReference - { - /// - /// Executes a mapping callback. - /// - /// The input context from the migration engine or previous mapping. - /// - /// The context, - /// potentially modified to pass on to the next mapping or migration engine, - /// or null to continue passing the same context as . - /// - new ContentMappingContext? Execute(ContentMappingContext ctx); - } -} diff --git a/src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncBulkPostPublishHook.cs b/src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncBulkPostPublishHook.cs deleted file mode 100644 index 0b8c7c6f..00000000 --- a/src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncBulkPostPublishHook.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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 Tableau.Migration.Engine.Hooks.PostPublish; - -namespace Tableau.Migration.Interop.Hooks.PostPublish -{ - /// - /// Interface representing a synchronous hook called when a migration attempt for bulk content items completes. - /// - /// - public interface ISyncBulkPostPublishHook - : ISyncMigrationHook>, IBulkPostPublishHook - { - /// - /// Executes a hook callback. - /// - /// The input context from the migration engine or previous hook. - /// - /// The context, - /// potentially modified to pass on to the next hook or migration engine, - /// or null to continue passing the same context as . - /// - new BulkPostPublishContext? Execute(BulkPostPublishContext ctx); - } -} diff --git a/src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHook.cs b/src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHook.cs deleted file mode 100644 index 05cb97a3..00000000 --- a/src/Tableau.Migration/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHook.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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 Tableau.Migration.Engine.Hooks.PostPublish; - -namespace Tableau.Migration.Interop.Hooks.PostPublish -{ - /// - /// Interface representing a synchronous hook called when a migration attempt for a single content item completes. - /// - /// - /// - public interface ISyncContentItemPostPublishHook - : ISyncMigrationHook>, IContentItemPostPublishHook - { - /// - /// Executes a hook callback. - /// - /// The input context from the migration engine or previous hook. - /// - /// The context, - /// potentially modified to pass on to the next hook or migration engine, - /// or null to continue passing the same context as . - /// - new ContentItemPostPublishContext? Execute(ContentItemPostPublishContext ctx); - } -} diff --git a/src/Tableau.Migration/Interop/Hooks/Transformers/ISyncContentTransformer.cs b/src/Tableau.Migration/Interop/Hooks/Transformers/ISyncContentTransformer.cs deleted file mode 100644 index 0e5e540f..00000000 --- a/src/Tableau.Migration/Interop/Hooks/Transformers/ISyncContentTransformer.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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 Tableau.Migration.Engine.Hooks.Transformers; - -namespace Tableau.Migration.Interop.Hooks.Transformers -{ - /// - /// Interface for an object that can synchronously modify or transform content of a specific content type during a migration. - /// - /// - public interface ISyncContentTransformer - : ISyncMigrationHook, IContentTransformer - { - /// - /// Executes a transformer callback. - /// - /// The input context from the migration engine or previous transformer. - /// - /// The context, - /// potentially modified to pass on to the next transformer or migration engine, - /// or null to continue passing the same context as . - /// - new TPublish? Execute(TPublish ctx); - } -} diff --git a/src/Tableau.Migration/Interop/Hooks/Transformers/ISyncXmlContentTransformer.cs b/src/Tableau.Migration/Interop/Hooks/Transformers/ISyncXmlContentTransformer.cs deleted file mode 100644 index 715e61cf..00000000 --- a/src/Tableau.Migration/Interop/Hooks/Transformers/ISyncXmlContentTransformer.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; -using Tableau.Migration.Content; -using Tableau.Migration.Engine.Hooks.Transformers; - -namespace Tableau.Migration.Interop.Hooks.Transformers -{ - /// - /// Interface for a content transformer that can synchronously manipulate the Tableau XML file of a content item. - /// - /// - public interface ISyncXmlContentTransformer : IXmlContentTransformer - where TPublish : IFileContent - { - /// - /// Finds whether the content item needs any XML changes, - /// returning false prevents file IO from occurring. - /// - /// The content item to inspect. - /// Whether or not the content item needs XML changes. - new bool NeedsXmlTransforming(TPublish ctx); - - /// - bool IXmlContentTransformer.NeedsXmlTransforming(TPublish ctx) => NeedsXmlTransforming(ctx); - - /// - /// Transforms the XML of the content item. - /// - /// The content item being transformed. - /// - /// The XML of the content item to transform. - /// Any changes made to the XML are persisted back to the file before publishing. - /// - void Transform(TPublish ctx, XDocument xml); - - /// - Task IXmlContentTransformer.TransformAsync(TPublish ctx, XDocument xml, CancellationToken cancel) - => Task.Run(() => Transform(ctx, xml), cancel); - } -} diff --git a/src/Tableau.Migration/Interop/InteropHelper.cs b/src/Tableau.Migration/Interop/InteropHelper.cs index f517a1e2..5055392d 100644 --- a/src/Tableau.Migration/Interop/InteropHelper.cs +++ b/src/Tableau.Migration/Interop/InteropHelper.cs @@ -41,15 +41,27 @@ public static class InteropHelper "$" }; + //DNG modify this to be less naive + //- Find if the generic has a Constraint, then build the types with that generic private static Type MakeSampleGenericType(Type generic) { var genericTypes = generic.GetGenericArguments() - .Select(gt => typeof(IUser)) + .Select(gt => + { + var constraints = gt.GetGenericParameterConstraints(); + + if (constraints.Length == 0) + { + return typeof(IUser); + } + + return constraints.First(); + }) .ToArray(); return generic.MakeGenericType(genericTypes); } - + private static bool IsPropertyMethod(MethodInfo method) => method.Name.StartsWith("get_") || method.Name.StartsWith("set_"); @@ -86,7 +98,7 @@ public static IEnumerable GetMethods(Type type) } /// - /// Gets the properies of a class. + /// Gets the properties of a class. /// /// The type to get properties from. /// The property names. @@ -94,7 +106,7 @@ public static IEnumerable GetProperties() => GetProperties(typeof(T)); /// - /// Gets the properies of a class. + /// Gets the properties of a class. /// /// The type to get properties from. /// The property names. diff --git a/src/Tableau.Migration/NameOf.cs b/src/Tableau.Migration/NameOf.cs index d6680312..7f8599b4 100644 --- a/src/Tableau.Migration/NameOf.cs +++ b/src/Tableau.Migration/NameOf.cs @@ -36,7 +36,7 @@ internal static class NameOf /// /// The expression to generate the member chain string for. /// - public static string Build(Expression> expression) => Build(expression.Body); + public static string Build(Expression> expression) => Build(expression.Body); private static string Build(Expression? expression) { diff --git a/src/Tableau.Migration/Net/IHttpStreamProcessor.cs b/src/Tableau.Migration/Net/IHttpStreamProcessor.cs index 5bbd3bea..970133b1 100644 --- a/src/Tableau.Migration/Net/IHttpStreamProcessor.cs +++ b/src/Tableau.Migration/Net/IHttpStreamProcessor.cs @@ -38,7 +38,7 @@ public interface IHttpStreamProcessor /// Function to build an HTTP request from a chunk of data from the stream. /// The first parameter is the chunk of data, or possibly a partial chunk of data. /// The second parameter is the count of bytes of the chunk of data to send. - /// A cancellation token to obey. + /// The cancellation token to obey. /// A collection of responses from the chunked requests. Task>> ProcessAsync( Stream stream, diff --git a/src/Tableau.Migration/Net/Simulation/IResponseSimulator.cs b/src/Tableau.Migration/Net/Simulation/IResponseSimulator.cs index a29447c2..944e751e 100644 --- a/src/Tableau.Migration/Net/Simulation/IResponseSimulator.cs +++ b/src/Tableau.Migration/Net/Simulation/IResponseSimulator.cs @@ -30,7 +30,7 @@ public interface IResponseSimulator /// Creates a simulated response for the request. /// /// The request to respond to. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The simulated response message. Task RespondAsync(HttpRequestMessage request, CancellationToken cancellationToken); } diff --git a/src/Tableau.Migration/Net/Simulation/Responses/IResponseBuilder.cs b/src/Tableau.Migration/Net/Simulation/Responses/IResponseBuilder.cs index 154f9aae..e46ee9fa 100644 --- a/src/Tableau.Migration/Net/Simulation/Responses/IResponseBuilder.cs +++ b/src/Tableau.Migration/Net/Simulation/Responses/IResponseBuilder.cs @@ -35,7 +35,7 @@ public interface IResponseBuilder /// Builds a HTTP response for the given request. /// /// The HTTP request to respond to. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The HTTP response. Task RespondAsync(HttpRequestMessage request, CancellationToken cancel); } diff --git a/src/Tableau.Migration/Paging/IPager.cs b/src/Tableau.Migration/Paging/IPager.cs index 75e72bac..827bd8ef 100644 --- a/src/Tableau.Migration/Paging/IPager.cs +++ b/src/Tableau.Migration/Paging/IPager.cs @@ -31,7 +31,7 @@ public interface IPager /// /// Gets a page of content. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The paged results. Task> NextPageAsync(CancellationToken cancel); @@ -40,7 +40,7 @@ public interface IPager /// /// An action to take once the first page is loaded and the total needed capacity is known. /// An action to take on each page. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The combined results. public async Task GetAllPagesAsync(Action initCapacity, Action> pageAction, CancellationToken cancel) { @@ -77,7 +77,7 @@ void ExecutePageAction(IPagedResult results) /// /// Combines all pages of content. /// - /// A cancellation token to obey. + /// The cancellation token to obey. /// The combined results. public async Task>> GetAllPagesAsync(CancellationToken cancel) { diff --git a/src/Tableau.Migration/Paging/IndexedPagerBase.cs b/src/Tableau.Migration/Paging/IndexedPagerBase.cs index b07f4e04..31c9b04a 100644 --- a/src/Tableau.Migration/Paging/IndexedPagerBase.cs +++ b/src/Tableau.Migration/Paging/IndexedPagerBase.cs @@ -47,7 +47,7 @@ public IndexedPagerBase(int pageSize, int defaultPageNumber = 1) /// /// The page number to get data for. /// The size of the page of data to get. - /// A cancellation token to obey. + /// The cancellation token to obey. /// The paged results. protected abstract Task> GetPageAsync(int pageNumber, int pageSize, CancellationToken cancel); diff --git a/src/Tableau.Migration/Resources/SharedResourceKeys.cs b/src/Tableau.Migration/Resources/SharedResourceKeys.cs index d4618e39..d84f5cc2 100644 --- a/src/Tableau.Migration/Resources/SharedResourceKeys.cs +++ b/src/Tableau.Migration/Resources/SharedResourceKeys.cs @@ -102,5 +102,11 @@ internal static class SharedResourceKeys public const string OwnerNotFoundMessage = "OwnerNotFoundMessage"; public const string FailedToGetDefaultPermissionsMessage = "FailedToGetDefaultPermissionsMessage"; + + public const string TableauInstanceTypeNotSupportedMessage = "TableauInstanceTypeNotSupportedMessage"; + + public const string MappedReferenceExtractRefreshTaskTransformerCannotFindReferenceWarning = "MappedReferenceExtractRefreshTaskTransformerCannotFindReferenceWarning"; + + public const string IntervalsChangedWarning = "IntervalsChangedWarning"; } } diff --git a/src/Tableau.Migration/Resources/SharedResources.resx b/src/Tableau.Migration/Resources/SharedResources.resx index bc462a34..4dfd1cd0 100644 --- a/src/Tableau.Migration/Resources/SharedResources.resx +++ b/src/Tableau.Migration/Resources/SharedResources.resx @@ -247,4 +247,15 @@ Detail: {4} Failed to get Default Permissions {UrlSegment} for {ProjectId}. + + The operation is not supported on {0}. + + + Could not update a reference to the destination Extract Refresh Task {ExtractRefreshTaskId}. Reason: Could not find the destination {ReferenceType} for {ReferenceId}. + + + The following intervals were changed for Extract Refresh Task ID {RefreshTaskId} due to cloud restrictions. +Server: {OldIntervals} +Cloud: {NewIntervals} + \ No newline at end of file diff --git a/src/Tableau.Migration/Tableau.Migration.csproj b/src/Tableau.Migration/Tableau.Migration.csproj index 34d03f28..fe480a84 100644 --- a/src/Tableau.Migration/Tableau.Migration.csproj +++ b/src/Tableau.Migration/Tableau.Migration.csproj @@ -45,16 +45,16 @@ Note: This SDK is specific for migrating from Tableau Server to Tableau Cloud. I - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/tests/Python.TestApplication/Python.TestApplication.pyproj b/tests/Python.TestApplication/Python.TestApplication.pyproj index 2e82ee2d..443cfbb6 100644 --- a/tests/Python.TestApplication/Python.TestApplication.pyproj +++ b/tests/Python.TestApplication/Python.TestApplication.pyproj @@ -36,6 +36,7 @@ + diff --git a/tests/Python.TestApplication/main.py b/tests/Python.TestApplication/main.py index 6f9811ba..0dfbc956 100644 --- a/tests/Python.TestApplication/main.py +++ b/tests/Python.TestApplication/main.py @@ -51,6 +51,7 @@ # SkipAllProjectsFilter, # SkipAllDataSourcesFilter, # SkipAllWorkbooksFilter, + # SkipAllExtractRefreshTasksFilter, # Skip Filters: Uncomment when neccesary. SkipProjectByParentLocationFilter, SkipDataSourceByParentLocationFilter, @@ -221,6 +222,7 @@ def migrate(self): # plan_builder.filters.add(SkipAllProjectsFilter) # plan_builder.filters.add(SkipAllDataSourcesFilter) # plan_builder.filters.add(SkipAllWorkbooksFilter) + # plan_builder.filters.add(SkipAllExtractRefreshTasksFilter) # Skip Filters: Uncomment when neccesary. # Load manifest if available diff --git a/tests/Python.TestApplication/migration_testcomponents_filters.py b/tests/Python.TestApplication/migration_testcomponents_filters.py index 20842208..ffbcc7c7 100644 --- a/tests/Python.TestApplication/migration_testcomponents_filters.py +++ b/tests/Python.TestApplication/migration_testcomponents_filters.py @@ -28,6 +28,7 @@ IDataSource, IGroup, IProject, + IServerExtractRefreshTask, IUser, IWorkbook, LicenseLevels @@ -124,6 +125,18 @@ def should_migrate(self, item: ContentMigrationItem[IWorkbook]) -> bool: self.logger.debug('%s is filtering "%s"', self.__class__.__name__, item.source_item.name) return False +class SkipAllExtractRefreshTasksFilter(ContentFilterBase[IServerExtractRefreshTask]): # noqa: N801 + """A class to filter all extract refresh tasks.""" + + def __init__(self): + """Default init to set up logging.""" + self.logger = logging.getLogger(self.__class__.__name__) + self.logger.setLevel(logging.DEBUG) + + def should_migrate(self, item: ContentMigrationItem[IServerExtractRefreshTask]) -> bool: + self.logger.debug('%s is filtering "%s"', self.__class__.__name__, item.source_item.name) + return False + TContent = TypeVar("TContent") class _SkipContentByParentLocationFilter(Generic[TContent]): # noqa: N801 diff --git a/tests/Python.TestApplication/pyproject.toml b/tests/Python.TestApplication/pyproject.toml index 2a266ed4..515ab50d 100644 --- a/tests/Python.TestApplication/pyproject.toml +++ b/tests/Python.TestApplication/pyproject.toml @@ -14,12 +14,11 @@ classifiers = [ ] dependencies = [ - "typing_extensions==4.9.0", + "typing_extensions==4.12.2", "cffi==1.16.0", - "clr-loader==0.2.6", - "pycparser==2.21", + "pycparser==2.22", "pythonnet==3.0.3", - "configparser==6.0.0" + "configparser==7.0.0" ] [tool.ruff] @@ -30,7 +29,7 @@ ignore = ["D401", "D407", "E501", "D203", "D212"] [tool.hatch.envs.test] dev-mode = false dependencies = [ - "pytest==8.0.1" + "pytest>=8.2.2" ] [tool.hatch.envs.test.scripts] diff --git a/tests/Python.TestApplication/requirements.txt b/tests/Python.TestApplication/requirements.txt index 2655ae56..9cddc614 100644 --- a/tests/Python.TestApplication/requirements.txt +++ b/tests/Python.TestApplication/requirements.txt @@ -1,5 +1,5 @@ -typing_extensions==4.9.0 +typing_extensions==4.12.2 cffi==1.16.0 -pycparser==2.21 +pycparser==2.22 pythonnet==3.0.3 -configparser==6.0.0 +configparser==7.0.0 diff --git a/tests/Tableau.Migration.TestApplication/Hooks/RemoveMissingDestinationUsersFromGroupsTransformer.cs b/tests/Tableau.Migration.TestApplication/Hooks/RemoveMissingDestinationUsersFromGroupsTransformer.cs index c37a7ec8..0793bde9 100644 --- a/tests/Tableau.Migration.TestApplication/Hooks/RemoveMissingDestinationUsersFromGroupsTransformer.cs +++ b/tests/Tableau.Migration.TestApplication/Hooks/RemoveMissingDestinationUsersFromGroupsTransformer.cs @@ -31,8 +31,8 @@ class RemoveMissingDestinationUsersFromGroupsTransformer : ContentTransformerBas private readonly IDestinationContentReferenceFinder _destinationUserContentReferenceFinder; public RemoveMissingDestinationUsersFromGroupsTransformer( - ISharedResourcesLocalizer? localizer, - ILogger>? logger, + ISharedResourcesLocalizer localizer, + ILogger> logger, IDestinationContentReferenceFinderFactory destinationContentReferenceFinderFactory) : base(localizer, logger) { diff --git a/tests/Tableau.Migration.TestApplication/Hooks/SkipFilter.cs b/tests/Tableau.Migration.TestApplication/Hooks/SkipFilter.cs index 65eec693..e63a0678 100644 --- a/tests/Tableau.Migration.TestApplication/Hooks/SkipFilter.cs +++ b/tests/Tableau.Migration.TestApplication/Hooks/SkipFilter.cs @@ -17,17 +17,20 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Tableau.Migration.Engine; -using Tableau.Migration.Interop.Hooks.Filters; +using Tableau.Migration.Engine.Hooks.Filters; namespace Tableau.Migration.TestApplication.Hooks { - class SkipFilter : ISyncContentFilter + class SkipFilter : IContentFilter where TContent : IContentReference { - public IEnumerable>? Execute(IEnumerable> ctx) + public Task>?> ExecuteAsync(IEnumerable> ctx, CancellationToken token) { - return Enumerable.Empty>(); + return Task.FromResult>?>( + Enumerable.Empty>()); } } } diff --git a/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj b/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj index 39ed68e1..a3a15b26 100644 --- a/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj +++ b/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj @@ -11,14 +11,15 @@ + - - + + - - - + + + diff --git a/tests/Tableau.Migration.TestApplication/TestApplication.cs b/tests/Tableau.Migration.TestApplication/TestApplication.cs index 54bd5d32..7ff3a386 100644 --- a/tests/Tableau.Migration.TestApplication/TestApplication.cs +++ b/tests/Tableau.Migration.TestApplication/TestApplication.cs @@ -15,21 +15,22 @@ // limitations under the License. // -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using System; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Engine.Manifest; using Tableau.Migration.Engine.Pipelines; using Tableau.Migration.TestApplication.Config; -using Tableau.Migration.TestComponents.Engine.Manifest; using Tableau.Migration.TestApplication.Hooks; -using Tableau.Migration.Engine.Manifest; +using Tableau.Migration.TestComponents.Engine.Manifest; namespace Tableau.Migration.TestApplication { @@ -102,6 +103,7 @@ public async Task StartAsync(CancellationToken cancel) _planBuilder.Hooks.Add>(); _planBuilder.Hooks.Add>(); _planBuilder.Hooks.Add>(); + _planBuilder.Hooks.Add>(); // Log when a content type is done _planBuilder.Hooks.Add(); @@ -120,6 +122,7 @@ public async Task StartAsync(CancellationToken cancel) //_planBuilder.Filters.Add(new SkipFilter()); //_planBuilder.Filters.Add(new SkipFilter()); //_planBuilder.Filters.Add(new SkipFilter()); + //_planBuilder.Filters.Add(new SkipFilter()); var prevManifest = await LoadManifest(_options.PreviousManifestPath, cancel); @@ -161,11 +164,11 @@ private void PrintResult(MigrationResult result) var typeResult = result.Manifest.Entries.ForContentType(contentType); var countTotal = typeResult.Count; - var countMigrated = typeResult.Where(x => x.Status == Engine.Manifest.MigrationManifestEntryStatus.Migrated).Count(); - var countSkipped = typeResult.Where(x => x.Status == Engine.Manifest.MigrationManifestEntryStatus.Skipped).Count(); - var countErrored = typeResult.Where(x => x.Status == Engine.Manifest.MigrationManifestEntryStatus.Error).Count(); - var countCancelled = typeResult.Where(x => x.Status == Engine.Manifest.MigrationManifestEntryStatus.Canceled).Count(); - var countPending = typeResult.Where(x => x.Status == Engine.Manifest.MigrationManifestEntryStatus.Pending).Count(); + var countMigrated = typeResult.Where(x => x.Status == MigrationManifestEntryStatus.Migrated).Count(); + var countSkipped = typeResult.Where(x => x.Status == MigrationManifestEntryStatus.Skipped).Count(); + var countErrored = typeResult.Where(x => x.Status == MigrationManifestEntryStatus.Error).Count(); + var countCancelled = typeResult.Where(x => x.Status == MigrationManifestEntryStatus.Canceled).Count(); + var countPending = typeResult.Where(x => x.Status == MigrationManifestEntryStatus.Pending).Count(); StringBuilder sb = new StringBuilder(); sb.AppendLine($"{contentType.Name}"); diff --git a/tests/Tableau.Migration.TestApplication/appsettings.json b/tests/Tableau.Migration.TestApplication/appsettings.json index e4b8f2d5..8ec77b06 100644 --- a/tests/Tableau.Migration.TestApplication/appsettings.json +++ b/tests/Tableau.Migration.TestApplication/appsettings.json @@ -15,7 +15,7 @@ { "type": "user", "batchSize": 50, - "batchPublishingEnabled": true + "batchPublishingEnabled": false }, { "type": "group", @@ -32,6 +32,10 @@ { "type": "workbook", "batchSize": 50 + }, + { + "type": "serverextractrefreshtask", + "batchSize": 50 } ] }, diff --git a/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj b/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj index 4cb6f478..7a289810 100644 --- a/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj +++ b/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj @@ -12,17 +12,18 @@ - + + - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Tableau.Migration.TestComponents/Engine/Manifest/MigrationManifestSerializer.cs b/tests/Tableau.Migration.TestComponents/Engine/Manifest/MigrationManifestSerializer.cs index 36e63ea6..2d8c4f21 100644 --- a/tests/Tableau.Migration.TestComponents/Engine/Manifest/MigrationManifestSerializer.cs +++ b/tests/Tableau.Migration.TestComponents/Engine/Manifest/MigrationManifestSerializer.cs @@ -68,7 +68,7 @@ private JsonSerializerOptions MergeJsonOptions(JsonSerializerOptions? jsonOption /// /// The manifest to save. /// The file path to save the manifest to. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Optional JSON options to use. public async Task SaveAsync(IMigrationManifest manifest, string path, JsonSerializerOptions? jsonOptions = null) { @@ -93,7 +93,7 @@ await JsonSerializer.SerializeAsync(file, manifest, jsonOptions, default) /// Loads a manifest from JSON format. /// /// The file path to load the manifest from. - /// A cancellation token to obey. + /// The cancellation token to obey. /// Optional JSON options to use. /// The loaded , or null if the manifest could not be loaded. public async Task LoadAsync(string path, CancellationToken cancel, JsonSerializerOptions? jsonOptions = null) diff --git a/tests/Tableau.Migration.Tests/EnumDataAttribute.cs b/tests/Tableau.Migration.Tests/EnumDataAttribute.cs index 1ebb42e8..27d215b8 100644 --- a/tests/Tableau.Migration.Tests/EnumDataAttribute.cs +++ b/tests/Tableau.Migration.Tests/EnumDataAttribute.cs @@ -17,6 +17,8 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using System.Reflection; using Xunit.Sdk; @@ -25,9 +27,18 @@ namespace Tableau.Migration.Tests public class EnumDataAttribute : DataAttribute where TEnum : struct, Enum { + private readonly IImmutableSet _exclude; + + public EnumDataAttribute(params TEnum[] exclude) + { + _exclude = exclude.ToImmutableHashSet(); + } + public override IEnumerable GetData(MethodInfo testMethod) { - foreach (var value in Enum.GetValues()) + var values = Enum.GetValues().Where(e => !_exclude.Contains(e)); + + foreach (var value in values) { yield return new object[] { value }; } diff --git a/tests/Tableau.Migration.Tests/FixtureFactory.cs b/tests/Tableau.Migration.Tests/FixtureFactory.cs index 3b65fff5..3cc2fbcd 100644 --- a/tests/Tableau.Migration.Tests/FixtureFactory.cs +++ b/tests/Tableau.Migration.Tests/FixtureFactory.cs @@ -16,12 +16,17 @@ // using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using AutoFixture; using AutoFixture.AutoMoq; using Moq; using Tableau.Migration.Api.Rest.Models.Requests; using Tableau.Migration.Api.Rest.Models.Responses; +using Tableau.Migration.Content.Schedules; +using CloudResponses = Tableau.Migration.Api.Rest.Models.Responses.Cloud; +using ServerResponses = Tableau.Migration.Api.Rest.Models.Responses.Server; namespace Tableau.Migration.Tests { @@ -59,6 +64,64 @@ private static IFixture Customize(IFixture fixture) #endregion + #region - ScheduleResponse - + + // These properties should return DateTime strings instead of the default Guid-like ones. + fixture.Customize(composer => composer + .With(s => s.CreatedAt, () => fixture.Create()?.ToIso8601()) + .With(s => s.UpdatedAt, () => fixture.Create()?.ToIso8601()) + .With(s => s.NextRunAt, () => fixture.Create()?.ToIso8601())); + + SetupInterval(); + SetupInterval(); + SetupInterval(); + + SetupFrequencyDetails(); + SetupFrequencyDetails(); + SetupFrequencyDetails(); + + void SetupFrequencyDetails() + where TFrequencyDetails : IScheduleFrequencyDetailsType + { + fixture.Customize(composer => composer + .With(f => f.Start, () => fixture.Create()?.ToString()) + .With(f => f.End, () => fixture.Create()?.ToString())); + } + + void SetupInterval() + where TInterval : IScheduleIntervalType + { + fixture.Customize(composer => + { + var customized = composer + .Without(i => i.Minutes) + .Without(i => i.Hours) + .Without(i => i.WeekDay) + .Without(i => i.MonthDay); + + const string hours = nameof(IScheduleIntervalType.Hours); + const string minutes = nameof(IScheduleIntervalType.Minutes); + const string weekDay = nameof(IScheduleIntervalType.WeekDay); + const string monthDay = nameof(IScheduleIntervalType.MonthDay); + + var property = new[] { hours, minutes, weekDay, monthDay }.PickRandom(); + + return property switch + { + hours => customized.With(i => i.Hours, GetRandomValue(IntervalValues.HoursValues)), + minutes => customized.With(i => i.Minutes, GetRandomValue(IntervalValues.MinutesValues)), + weekDay => customized.With(i => i.WeekDay, GetRandomValue(IntervalValues.WeekDaysValues)), + monthDay => customized.With(i => i.MonthDay, GetRandomValue(IntervalValues.MonthDaysValues)), + _ => throw new NotSupportedException($"{nameof(property)} value {property} is not supported.") + }; + + static string GetRandomValue(IEnumerable values) + => values.Select(v => v?.ToString()).ExceptNulls().PickRandom(); + }); + } + + #endregion + #region - ImportJobResponse - // These properties should return DateTime strings instead of the default Guid-like ones. @@ -150,6 +213,58 @@ private static IFixture Customize(IFixture fixture) #endregion + #region - Server.ExtractRefreshTasksResponse - + + fixture.Customize( + composer + => composer + .With(j => j.CreatedAt, () => fixture.Create()?.ToIso8601()) + .With(j => j.UpdatedAt, () => fixture.Create()?.ToIso8601()) + .With(j => j.NextRunAt, () => fixture.Create()?.ToIso8601())); + + #endregion + + #region - Cloud.ExtractRefreshTasksResponse - + + fixture.Customize( + composer + => composer + .With(j => j.Start, () => fixture.Create()?.ToString()) + .With(j => j.End, () => fixture.Create()?.ToString())); + + #endregion + + #region - Cloud.CreateExtractRefreshTaskResponse - + + fixture.Customize( + composer + => composer + .With(j => j.NextRunAt, () => fixture.Create()?.ToIso8601())); + fixture.Customize( + composer + => composer + .With(j => j.Start, () => fixture.Create()?.ToString()) + .With(j => j.End, () => fixture.Create()?.ToString())); + + #endregion + + #region - Server.ScheduleExtractsResponse - + + string GetRandomExtractType() + { + var extractTypes = new List { "IncrementalRefresh", "FullRefresh" }; + var random = new Random(); + int index = random.Next(extractTypes.Count); + return extractTypes[index]; + } + + fixture.Customize( + composer + => composer + .With(j => j.Type, () => GetRandomExtractType()) + ); + #endregion + return fixture; } } diff --git a/tests/Tableau.Migration.Tests/IEnumerableExtensions.cs b/tests/Tableau.Migration.Tests/IEnumerableExtensions.cs index 5dffc26a..db9770d2 100644 --- a/tests/Tableau.Migration.Tests/IEnumerableExtensions.cs +++ b/tests/Tableau.Migration.Tests/IEnumerableExtensions.cs @@ -18,11 +18,20 @@ using System; using System.Collections.Generic; using System.Linq; +using Xunit; namespace Tableau.Migration.Tests { public static class IEnumerableExtensions { + private static readonly Lazy _random = new(); + + public static T PickRandom(this IEnumerable c) + { + var randomIndex = _random.Value.Next(0, c.Count() - 1); + return c.ElementAt(randomIndex); + } + /// /// Determine if two sequences are equal ignoring ordering. /// @@ -41,5 +50,20 @@ public static bool SequenceEqual(this IEnumerable? first, IEnumerable? return firstSorted.SequenceEqual(secondSorted); } + + /// + /// Asserts that all items in the collection are the same. + /// + /// The collection type. + /// The values to compare. + public static void AssertAllSame(this IEnumerable values) + where T : class + => Assert.All( + values, + (v, i) => + { + if (i > 0) + Assert.Same(values.ElementAt(i - 1), v); + }); } } diff --git a/tests/Tableau.Migration.Tests/Simulation/MultiDestinationSimulationTestBase.cs b/tests/Tableau.Migration.Tests/Simulation/MultiDestinationSimulationTestBase.cs index 211d117e..25e12bd4 100644 --- a/tests/Tableau.Migration.Tests/Simulation/MultiDestinationSimulationTestBase.cs +++ b/tests/Tableau.Migration.Tests/Simulation/MultiDestinationSimulationTestBase.cs @@ -44,12 +44,12 @@ public abstract class MultiDestinationSimulationTestBase : SimulationTestBase public MultiDestinationSimulationTestBase(string sourceUrl, IEnumerable destinationUrls) { - SourceApi = RegisterApiSimulator(sourceUrl, Create()); + SourceApi = RegisterTableauServerApiSimulator(sourceUrl, Create()); SourceSiteConfig = BuildSiteConnectionConfiguration(SourceApi); SourceEndpointConfig = new(SourceSiteConfig); DestinationApis = destinationUrls - .Select(u => RegisterApiSimulator(u, Create())) + .Select(u => RegisterTableauServerApiSimulator(u, Create())) .ToImmutableArray(); DestinationSiteConfigs = DestinationApis diff --git a/tests/Tableau.Migration.Tests/Simulation/ServerToCloudSimulationTestBase.cs b/tests/Tableau.Migration.Tests/Simulation/ServerToCloudSimulationTestBase.cs index 8dde7933..1a31b9da 100644 --- a/tests/Tableau.Migration.Tests/Simulation/ServerToCloudSimulationTestBase.cs +++ b/tests/Tableau.Migration.Tests/Simulation/ServerToCloudSimulationTestBase.cs @@ -19,7 +19,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; using AutoFixture; using Microsoft.Extensions.DependencyInjection; using Moq; @@ -36,6 +35,7 @@ using Tableau.Migration.Tests.Content.Permissions; using Tableau.Migration.Tests.Unit.Content.Permissions; using Xunit; +using Server = Tableau.Migration.Api.Rest.Models.Responses.Server; namespace Tableau.Migration.Tests.Simulation { @@ -72,11 +72,11 @@ UsersResponse.UserType CreateDefaultUser() return defaultUser; } - SourceApi = RegisterApiSimulator(sourceUrl, CreateDefaultUser()); + SourceApi = RegisterTableauServerApiSimulator(sourceUrl, CreateDefaultUser()); SourceSiteConfig = BuildSiteConnectionConfiguration(SourceApi); SourceEndpointConfig = new(SourceSiteConfig); - CloudDestinationApi = RegisterCloudApiSimulator(destinationUrl, CreateDefaultUser()); + CloudDestinationApi = RegisterTableauCloudApiSimulator(destinationUrl, CreateDefaultUser()); CloudDestinationSiteConfig = BuildSiteConnectionConfiguration(CloudDestinationApi); CloudDestinationEndpointConfig = new(CloudDestinationSiteConfig); } @@ -361,7 +361,7 @@ protected static void AssertPermissionsMigrated(IMigrationManifest manifest, Per return dataSources; } - #endregion - Prepare Source Data (Projects) - + #endregion - Prepare Source Data (Data Sources) - #region - Prepare Source Data (Workbooks) - @@ -493,6 +493,7 @@ void CreateConnectionsForWorkbook(SimulatedWorkbookData workbookData, int connec SourceApi.Data.AddWorkbook(workbook, Constants.DefaultEncoding.GetBytes(workbookFileData.ToXml())); workbooks.Add(workbook); + counter++; } return workbooks; @@ -500,5 +501,188 @@ void CreateConnectionsForWorkbook(SimulatedWorkbookData workbookData, int connec #endregion - Prepare Source Data (Workbooks) - + #region - Prepare Source Data (Schedules) - + + private List PrepareSchedulesData() + { + var hourlySchedule = new Server.ScheduleResponse.ScheduleType + { + Id = Guid.NewGuid(), + Name = ScheduleFrequencies.Hourly, + Type = ScheduleTypes.Extract, + Frequency = ScheduleFrequencies.Hourly, + State = "Active", + Priority = 50, + ExecutionOrder = "Parallel", + FrequencyDetails = new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType + { + Start = "00:25:00", + End = "01:25:00", + Intervals = [ + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { Hours = "1" }, + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { WeekDay = WeekDays.Sunday }, + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { WeekDay = WeekDays.Saturday } + ] + } + }; + var dailySchedule = new Server.ScheduleResponse.ScheduleType + { + Id = Guid.NewGuid(), + Name = ScheduleFrequencies.Daily, + Type = ScheduleTypes.Extract, + Frequency = ScheduleFrequencies.Daily, + State = "Active", + Priority = 50, + ExecutionOrder = "Parallel", + FrequencyDetails = new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType + { + Start = "00:15:00", + End = "12:15:00", + Intervals = [ + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { Hours = "12" }, + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { WeekDay = WeekDays.Tuesday }, + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { WeekDay = WeekDays.Thursday } + ] + } + }; + var weeklySchedule = new Server.ScheduleResponse.ScheduleType + { + Id = Guid.NewGuid(), + Name = ScheduleFrequencies.Weekly, + Type = ScheduleTypes.Extract, + Frequency = ScheduleFrequencies.Weekly, + State = "Active", + Priority = 50, + ExecutionOrder = "Parallel", + FrequencyDetails = new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType + { + Start = "03:10:00", + Intervals = [new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { WeekDay = WeekDays.Sunday }] + } + }; + var monthlyMultipleDaysSchedule = new Server.ScheduleResponse.ScheduleType + { + Id = Guid.NewGuid(), + Name = $"{ScheduleFrequencies.Monthly}_Multiple", + Type = ScheduleTypes.Extract, + Frequency = ScheduleFrequencies.Monthly, + State = "Active", + Priority = 50, + ExecutionOrder = "Parallel", + FrequencyDetails = new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType + { + Start = "03:45:00", + Intervals = [ + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { MonthDay = "1" }, + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { MonthDay = "10" }, + new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { MonthDay = "20" } + ] + } + }; + var monthlyLastSundaySchedule = new Server.ScheduleResponse.ScheduleType + { + Id = Guid.NewGuid(), + Name = $"{ScheduleFrequencies.Monthly}_LastSunday", + Type = ScheduleTypes.Extract, + Frequency = ScheduleFrequencies.Monthly, + State = "Active", + Priority = 50, + ExecutionOrder = "Parallel", + FrequencyDetails = new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType + { + Start = "01:35:00", + Intervals = [new Server.ScheduleResponse.ScheduleType.FrequencyDetailsType.IntervalType { WeekDay = WeekDays.Sunday, MonthDay="LastDay" }] + } + }; + var schedules = new List + { + hourlySchedule, + dailySchedule, + weeklySchedule, + monthlyMultipleDaysSchedule, + monthlyLastSundaySchedule + }; + + foreach (var schedule in schedules) + { + SourceApi.Data.AddSchedule(schedule); + } + + return schedules; + } + + #endregion - Prepare Source Data (Schedules) - + + #region - Prepare Source Data (ExtractRefreshTasks) - + + protected List PrepareSourceExtractRefreshTasksData() + { + var extractRefreshTasks = new List(); + + var schedules = PrepareSchedulesData(); + + var count = 0; + foreach (var datasource in SourceApi.Data.DataSources) + { + extractRefreshTasks.Add( + new Server.ExtractRefreshTasksResponse.TaskType + { + ExtractRefresh = new Server.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType + { + Id = Guid.NewGuid(), + Priority = 50, + DataSource = new Server.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.DataSourceType + { + Id = datasource.Id + }, + Schedule = new Server.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.ScheduleType + { + Id = schedules[count % schedules.Count].Id + } + } + }); + count++; + } + + foreach (var workbook in SourceApi.Data.Workbooks) + { + extractRefreshTasks.Add( + new Server.ExtractRefreshTasksResponse.TaskType + { + ExtractRefresh = new Server.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType + { + Id = Guid.NewGuid(), + Priority = 50, + Workbook = new Server.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.WorkbookType + { + Id = workbook.Id + }, + Schedule = new Server.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.ScheduleType + { + Id = schedules[count % schedules.Count].Id + } + } + }); + count++; + } + + foreach (var extractRefreshTask in extractRefreshTasks) + { + var schedule = schedules.First(sch => sch.Id == extractRefreshTask.ExtractRefresh!.Schedule!.Id); + SourceApi.Data.ServerExtractRefreshTasks.Add(extractRefreshTask); + SourceApi.Data.AddExtractToSchedule( + new Server.ScheduleExtractRefreshTasksResponse.ExtractType + { + Id = extractRefreshTask.ExtractRefresh!.Id, + Type = count % 2 == 0 ? ExtractRefreshType.FullRefresh : ExtractRefreshType.ServerIncrementalRefresh + }, + schedule); + count++; + } + + return extractRefreshTasks; + } + + #endregion - Prepare Source Data (ExtractRefreshTasks) - } } diff --git a/tests/Tableau.Migration.Tests/Simulation/ServerToServerSimulationTestBase.cs b/tests/Tableau.Migration.Tests/Simulation/ServerToServerSimulationTestBase.cs index 9ba43791..55cd7dde 100644 --- a/tests/Tableau.Migration.Tests/Simulation/ServerToServerSimulationTestBase.cs +++ b/tests/Tableau.Migration.Tests/Simulation/ServerToServerSimulationTestBase.cs @@ -41,11 +41,11 @@ public abstract class ServerToServerSimulationTestBase : SimulationTestBase public ServerToServerSimulationTestBase(string sourceUrl = "https://source", string destinationUrl = "https://destination") { - SourceApi = RegisterApiSimulator(sourceUrl, Create()); + SourceApi = RegisterTableauServerApiSimulator(sourceUrl, Create()); SourceSiteConfig = BuildSiteConnectionConfiguration(SourceApi); SourceEndpointConfig = new(SourceSiteConfig); - DestinationApi = RegisterApiSimulator(destinationUrl, Create()); + DestinationApi = RegisterTableauServerApiSimulator(destinationUrl, Create()); DestinationSiteConfig = BuildSiteConnectionConfiguration(DestinationApi); DestinationEndpointConfig = new(DestinationSiteConfig); } diff --git a/tests/Tableau.Migration.Tests/Simulation/SimulationTestBase.cs b/tests/Tableau.Migration.Tests/Simulation/SimulationTestBase.cs index 06bf2eb9..7b498444 100644 --- a/tests/Tableau.Migration.Tests/Simulation/SimulationTestBase.cs +++ b/tests/Tableau.Migration.Tests/Simulation/SimulationTestBase.cs @@ -68,11 +68,21 @@ protected SimulationTestBase() /// Registers a for HTTP request/response mocking. /// /// The URI of the server. - /// /// Default signed in user. If null, no user will be created or signed in. - protected TableauApiSimulator RegisterApiSimulator(Uri serverUri, - UsersResponse.UserType? defaultSignedInUser, string defaultDomain = Constants.LocalDomain) + /// Indicates whether the current Tableau Data is for Tableau Server (true) or Tableau Cloud (false). + /// Default signed in user. If null, no user will be created or signed in. + /// The default domain of the site. + protected TableauApiSimulator RegisterApiSimulator( + Uri serverUri, + bool isTableauServer, + UsersResponse.UserType? defaultSignedInUser, + string defaultDomain = Constants.LocalDomain) { - var simulator = new TableauApiSimulator(serverUri, Serializer, defaultSignedInUser, defaultDomain); + var simulator = new TableauApiSimulator( + serverUri, + Serializer, + isTableauServer, + defaultSignedInUser, + defaultDomain); ApiSimulators.AddOrUpdate(simulator); return simulator; } @@ -86,19 +96,30 @@ protected TableauSiteConnectionConfiguration BuildSiteConnectionConfiguration(Ta } /// - /// Registers a for HTTP request/response mocking. + /// Registers a Tableau Server for HTTP request/response mocking. /// /// The URL of the server. /// Default signed in user. If null, no user will be created or signed in. - protected TableauApiSimulator RegisterApiSimulator(string serverUrl, UsersResponse.UserType? defaultSignedInUser) - => RegisterApiSimulator(new Uri(serverUrl), defaultSignedInUser); + protected TableauApiSimulator RegisterTableauServerApiSimulator( + string serverUrl, + UsersResponse.UserType? defaultSignedInUser) + => RegisterApiSimulator( + new Uri(serverUrl), + true, + defaultSignedInUser); /// /// Registers a Tableau Cloud for HTTP request/response mocking. /// /// Default signed in user. If null, no user will be created or signed in. - protected TableauApiSimulator RegisterCloudApiSimulator(string podUrl, UsersResponse.UserType? defaultSignedInUser) - => RegisterApiSimulator(new Uri(podUrl), defaultSignedInUser, Constants.TableauIdWithMfaDomain); + protected TableauApiSimulator RegisterTableauCloudApiSimulator( + string podUrl, + UsersResponse.UserType? defaultSignedInUser) + => RegisterApiSimulator( + new Uri(podUrl), + false, + defaultSignedInUser, + Constants.TableauIdWithMfaDomain); public async ValueTask DisposeAsync() { diff --git a/tests/Tableau.Migration.Tests/Simulation/SingleServerSimulationTestBase.cs b/tests/Tableau.Migration.Tests/Simulation/SingleServerSimulationTestBase.cs index 1661bd2d..2da1317d 100644 --- a/tests/Tableau.Migration.Tests/Simulation/SingleServerSimulationTestBase.cs +++ b/tests/Tableau.Migration.Tests/Simulation/SingleServerSimulationTestBase.cs @@ -37,11 +37,11 @@ public SingleServerSimulationTestBase(bool isCloud = false) { if (isCloud) { - Api = RegisterCloudApiSimulator("https://destination", Create()); + Api = RegisterTableauCloudApiSimulator("https://destination", Create()); } else { - Api = RegisterApiSimulator("https://server", Create()); + Api = RegisterTableauServerApiSimulator("https://server", Create()); } SiteConfig = BuildSiteConnectionConfiguration(Api); diff --git a/tests/Tableau.Migration.Tests/Simulation/TableauDataExtensions.cs b/tests/Tableau.Migration.Tests/Simulation/TableauDataExtensions.cs index 393b26ea..9160ca9c 100644 --- a/tests/Tableau.Migration.Tests/Simulation/TableauDataExtensions.cs +++ b/tests/Tableau.Migration.Tests/Simulation/TableauDataExtensions.cs @@ -18,26 +18,18 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using System.Text; using AutoFixture; using Tableau.Migration.Api.Rest.Models.Responses; +using Tableau.Migration.Api.Rest.Models.Responses.Server; using Tableau.Migration.Api.Rest.Models.Types; using Tableau.Migration.Api.Simulation; using Tableau.Migration.Net; +using CloudResponse = Tableau.Migration.Api.Rest.Models.Responses.Cloud; namespace Tableau.Migration.Tests.Simulation { public static class TableauDataExtensions { - private static readonly Lazy _random = new(); - - public static T PickRandom(this ICollection c) - { - var randomIndex = _random.Value.Next(0, c.Count - 1); - return c.ElementAt(randomIndex); - } - public static DataSourceResponse.DataSourceType CreateDataSource( this TableauData data, IFixture autoFixture, @@ -214,5 +206,209 @@ public static ProjectsResponse.ProjectType CreateProject(this TableauData data, return projects.ToImmutableArray(); } + + public static ScheduleResponse.ScheduleType CreateSchedule( + this TableauData data, + IFixture autoFixture) + { + var schedule = autoFixture.Build() + .Create(); + + data.AddSchedule(schedule); + + return schedule; + } + + public static ScheduleResponse.ScheduleType CreateScheduleExtractRefreshTask( + this TableauData data, + IFixture autoFixture, + ScheduleResponse.ScheduleType? schedule = null, + Guid? extractRefreshId = null, + string? extractRefreshType = null) + { + if (schedule is null) + { + schedule = data.CreateSchedule(autoFixture); + } + + var composer = autoFixture.Build(); + + if (extractRefreshId.HasValue) + { + composer.With(sert => sert.Id, extractRefreshId); + } + + if (!extractRefreshType.IsNullOrEmpty()) + { + composer.With(sert => sert.Type, extractRefreshType); + } + + var extractRefreshSchedule = composer.Create(); + + data.AddExtractToSchedule( + extractRefreshSchedule, + schedule); + + return schedule; + } + + public static ExtractRefreshTasksResponse.TaskType CreateServerExtractRefreshTask( + this TableauData data, + IFixture autoFixture, + DataSourceResponse.DataSourceType? dataSource = null, + WorkbookResponse.WorkbookType? workbook = null) + { + var schedule = data.CreateScheduleExtractRefreshTask(autoFixture); + + var extractRefreshComposer = autoFixture + .Build() + .With(ert => ert.Schedule, () => new ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.ScheduleType + { + Id = schedule.Id + }); + + if (dataSource is not null) + { + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.Workbook, () => new ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.WorkbookType + { + Id = workbook!.Id + }) + .Without(ert => ert.DataSource); + } + else if (workbook is not null) + { + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.DataSource, () => new ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.DataSourceType + { + Id = dataSource!.Id + }) + .Without(ert => ert.Workbook); + } + else + { + if (autoFixture.Create()) + { + var generatedDatasource = data.CreateDataSource(autoFixture); + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.DataSource, () => new ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.DataSourceType + { + Id = generatedDatasource!.Id + }) + .Without(ert => ert.Workbook); + } + else + { + var generatedWorkbook = data.CreateWorkbook(autoFixture); + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.Workbook, () => new ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.WorkbookType + { + Id = generatedWorkbook!.Id + }) + .Without(ert => ert.DataSource); + } + } + + var extractRefreshTask = autoFixture + .Build() + .With(tt => tt.ExtractRefresh, () => extractRefreshComposer.Create()) + .Create(); + + data.ServerExtractRefreshTasks.Add(extractRefreshTask); + + return extractRefreshTask; + } + + public static IImmutableList CreateServerExtractRefreshTasks( + this TableauData data, + IFixture autoFixture, + int extractRefreshCount) + { + var extractRefreshTasks = new List(); + + for (var i = 0; i != extractRefreshCount; i++) + { + extractRefreshTasks.Add(data.CreateServerExtractRefreshTask(autoFixture)); + } + + return extractRefreshTasks.ToImmutableArray(); + } + + public static CloudResponse.ExtractRefreshTasksResponse.TaskType CreateCloudExtractRefreshTask( + this TableauData data, + IFixture autoFixture, + DataSourceResponse.DataSourceType? dataSource = null, + WorkbookResponse.WorkbookType? workbook = null) + { + var extractRefreshComposer = autoFixture + .Build() + .With(ert => ert.Schedule); + + if (dataSource is not null) + { + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.Workbook, () => new CloudResponse.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.WorkbookType + { + Id = dataSource!.Id + }) + .Without(ert => ert.DataSource); + } + else if (workbook is not null) + { + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.DataSource, () => new CloudResponse.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.DataSourceType + { + Id = workbook!.Id + }) + .Without(ert => ert.Workbook); + } + else + { + if (autoFixture.Create()) + { + var generatedDatasource = data.CreateDataSource(autoFixture); + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.DataSource, () => new CloudResponse.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.DataSourceType + { + Id = generatedDatasource!.Id + }) + .Without(ert => ert.Workbook); + } + else + { + var generatedWorkbook = data.CreateWorkbook(autoFixture); + extractRefreshComposer = extractRefreshComposer + .With(ert => ert.Workbook, () => new CloudResponse.ExtractRefreshTasksResponse.TaskType.ExtractRefreshType.WorkbookType + { + Id = generatedWorkbook!.Id + }) + .Without(ert => ert.DataSource); + } + } + + var extractRefreshTask = autoFixture + .Build() + .With(tt => tt.ExtractRefresh, () => extractRefreshComposer.Create()) + .Create(); + + data.CloudExtractRefreshTasks.Add(extractRefreshTask); + + return extractRefreshTask; + } + + public static IImmutableList CreateCloudExtractRefreshTasks( + this TableauData data, + IFixture autoFixture, + int extractRefreshCount) + { + var extractRefreshTasks = new List(); + + for (var i = 0; i != extractRefreshCount; i++) + { + extractRefreshTasks.Add(data.CreateCloudExtractRefreshTask(autoFixture)); + } + + return extractRefreshTasks.ToImmutableArray(); + } } } diff --git a/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTestBase.cs b/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTestBase.cs index a6a6cc0a..8c3419d8 100644 --- a/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTestBase.cs +++ b/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTestBase.cs @@ -30,8 +30,8 @@ public abstract class ApiClientTestBase : SingleServerSimulationTestBase { internal readonly ApiClient ApiClient; - public ApiClientTestBase() - : base() + public ApiClientTestBase(bool isCloud = false) + : base(isCloud) { var apiInputInitializer = ServiceProvider.GetRequiredService(); apiInputInitializer.Initialize(SiteConfig); diff --git a/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTests.cs b/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTests.cs index c9098fcc..e5dccaad 100644 --- a/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTests.cs +++ b/tests/Tableau.Migration.Tests/Simulation/Tests/Api/ApiClientTests.cs @@ -32,6 +32,10 @@ public class ApiClientTests { public abstract class ApiClientTest : ApiClientTestBase { + public ApiClientTest(bool isCloud = false) + : base(isCloud) + { } + protected void AssertDefaultRestApiVersion(string? expectedVersion) { var versionProvider = ServiceProvider.GetRequiredService(); @@ -94,6 +98,56 @@ public async Task Returns_error_on_failure() } } + public class GetInstanceTypeForServerAsync : ApiClientTest + { + public GetInstanceTypeForServerAsync() + : base(false) + { } + + [Fact] + public async Task Returns_Tableau_Server() + { + var result = await ApiClient.GetInstanceTypeAsync(Cancel); + + Assert.Equal(TableauInstanceType.Server, result); + } + + [Fact] + public async Task Returns_Unknown() + { + Api.RestApi.QuerySites.RespondWithError(); + + var result = await ApiClient.GetInstanceTypeAsync(Cancel); + + Assert.Equal(TableauInstanceType.Unknown, result); + } + } + + public class GetInstanceTypeForCloudAsync : ApiClientTest + { + public GetInstanceTypeForCloudAsync() + : base(true) + { } + + [Fact] + public async Task Returns_Tableau_Cloud() + { + var result = await ApiClient.GetInstanceTypeAsync(Cancel); + + Assert.Equal(TableauInstanceType.Cloud, result); + } + + [Fact] + public async Task Returns_Unknown() + { + Api.RestApi.QuerySites.RespondWithError(); + + var result = await ApiClient.GetInstanceTypeAsync(Cancel); + + Assert.Equal(TableauInstanceType.Unknown, result); + } + } + public class SignInAsync : ApiClientTest { [Fact] diff --git a/tests/Tableau.Migration.Tests/Simulation/Tests/Api/SitesApiClientTests.cs b/tests/Tableau.Migration.Tests/Simulation/Tests/Api/SitesApiClientTests.cs index 9b0536c5..d3ccab9a 100644 --- a/tests/Tableau.Migration.Tests/Simulation/Tests/Api/SitesApiClientTests.cs +++ b/tests/Tableau.Migration.Tests/Simulation/Tests/Api/SitesApiClientTests.cs @@ -17,6 +17,7 @@ using System; using System.Threading.Tasks; +using Tableau.Migration.Api; using Tableau.Migration.Api.Rest; using Tableau.Migration.Api.Rest.Models.Responses; using Xunit; @@ -26,7 +27,11 @@ namespace Tableau.Migration.Tests.Simulation.Tests.Api public class SitesApiClientTests { public class SitesApiClientTest : ApiClientTestBase - { } + { + public SitesApiClientTest(bool isCloud = false) + : base(isCloud) + { } + } public class GetSiteAsync : SitesApiClientTest { @@ -98,5 +103,59 @@ public async Task NotFoundWithContentUrlAsync() Assert.IsType(error); } } + + public class GetTasksForServer : SitesApiClientTest + { + public GetTasksForServer() + : base(false) + { } + + [Fact] + public async Task GetServerTasks_Returns_ServerTasksApiClient() + { + // Arrange + await using var sitesClient = await GetSitesClientAsync(Cancel); + + // Act/Assert + Assert.IsAssignableFrom(sitesClient.ServerTasks); + } + + [Fact] + public async Task GetCloudTasks_Throws_Exception() + { + // Arrange + await using var sitesClient = await GetSitesClientAsync(Cancel); + + // Act/Assert + Assert.Throws(() => sitesClient.CloudTasks); + } + } + + public class GetTasksForCloud : SitesApiClientTest + { + public GetTasksForCloud() + : base(true) + { } + + [Fact] + public async Task GetServerTasks_Throws_Exception() + { + // Arrange + await using var sitesClient = await GetSitesClientAsync(Cancel); + + // Act/Assert + Assert.Throws(() => sitesClient.ServerTasks); + } + + [Fact] + public async Task GetCloudTasks_Returns_CloudTasksApiClient() + { + // Arrange + await using var sitesClient = await GetSitesClientAsync(Cancel); + + // Act/Assert + Assert.IsAssignableFrom(sitesClient.CloudTasks); + } + } } } diff --git a/tests/Tableau.Migration.Tests/Simulation/Tests/WorkbookMigrationTests.cs b/tests/Tableau.Migration.Tests/Simulation/Tests/WorkbookMigrationTests.cs index 0010cf92..f4f8ce71 100644 --- a/tests/Tableau.Migration.Tests/Simulation/Tests/WorkbookMigrationTests.cs +++ b/tests/Tableau.Migration.Tests/Simulation/Tests/WorkbookMigrationTests.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Tableau.Migration.Api.Rest.Models.Responses; diff --git a/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj b/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj index 09f23bda..91ab1fba 100644 --- a/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj +++ b/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj @@ -10,29 +10,30 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Tableau.Migration.Tests/TestContentType.cs b/tests/Tableau.Migration.Tests/TestContentType.cs index 302257c2..a3411ebe 100644 --- a/tests/Tableau.Migration.Tests/TestContentType.cs +++ b/tests/Tableau.Migration.Tests/TestContentType.cs @@ -29,9 +29,23 @@ public class TestContentType : IContentReference public string Name => Location.Name; + public TestContentType() + { } + + public TestContentType(IContentReference reference) + { + Id = reference.Id; + ContentUrl = reference.ContentUrl; + Location = reference.Location; + } + public bool Equals(IContentReference? other) { - throw new NotImplementedException(); + return other is not null && + Id.Equals(other.Id) && + ContentUrl == other.ContentUrl && + Location.Equals(other.Location) && + Name == other.Name; } } diff --git a/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTestDependencies.cs b/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTestDependencies.cs index a4584f6e..406da3ae 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTestDependencies.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTestDependencies.cs @@ -26,6 +26,7 @@ using Tableau.Migration.Api.Tags; using Tableau.Migration.Config; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Net; using Tableau.Migration.Net.Rest; @@ -46,7 +47,8 @@ internal class ApiClientTestDependencies : IDisposable, IApiClientTestDependenci public Mock MockLoggerFactory { get; } = new(); public Mock MockConfigReader { get; } = new(); public MockSharedResourcesLocalizer MockSharedResourcesLocalizer { get; } = new(); - public Mock MockContentFinderFactory { get; } = new(); + public Mock MockContentFinderFactory { get; } = new() { CallBase = true }; + public Mock MockContentCacheFactory { get; } = new(); public Mock MockPermissionsClientFactory { get; } = new(); public Mock MockTaskDelayer { get; } = new(); public TestHttpStreamProcessor HttpStreamProcessor { get; } @@ -64,8 +66,12 @@ internal class ApiClientTestDependencies : IDisposable, IApiClientTestDependenci public Mock MockLogger { get; } = new(); public Mock> MockProjectFinder { get; } - public Mock> MockUserFinder { get; } + public Mock> MockWorkbookFinder { get; } + public Mock> MockDataSourceFinder { get; } + public Mock> MockScheduleFinder { get; } + + public Mock> MockScheduleCache { get; } = new(); public TableauServerVersion TableauServerVersion { get; private set; } @@ -91,8 +97,13 @@ public ApiClientTestDependencies(IFixture autoFixture) .Returns(new MigrationSdkOptions()); MockProjectFinder = MockContentFinderFactory.SetupMockFinder(autoFixture); - MockUserFinder = MockContentFinderFactory.SetupMockFinder(autoFixture); + MockWorkbookFinder = MockContentFinderFactory.SetupMockFinder(autoFixture); + MockDataSourceFinder = MockContentFinderFactory.SetupMockFinder(autoFixture); + MockScheduleFinder = MockContentFinderFactory.SetupMockFinder(autoFixture); + + MockScheduleCache = MockContentCacheFactory.SetupMockCache(autoFixture); + MockApiClientInput.SetupGet(i => i.SiteConnectionConfiguration).Returns(SiteConnectionConfiguration); MockSessionProvider.SetupGet(p => p.Version).Returns(TableauServerVersion); @@ -134,6 +145,7 @@ private void ReplaceServices() ReplaceService(MockConfigReader); ReplaceService(MockSharedResourcesLocalizer); ReplaceService(MockContentFinderFactory); + ReplaceService(MockContentCacheFactory); ReplaceService(MockPermissionsClientFactory); ReplaceService(MockDataSourcePublisher); ReplaceService(MockWorkbookPublisher); diff --git a/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTests.cs index b78c1ae7..9afc129a 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/ApiClientTests.cs @@ -15,12 +15,15 @@ // limitations under the License. // +using System.Net; +using System.Net.Http; using System.Threading.Tasks; using Moq; using Tableau.Migration.Api; using Tableau.Migration.Api.Models; using Tableau.Migration.Api.Rest.Models.Requests; using Tableau.Migration.Api.Rest.Models.Responses; +using Tableau.Migration.Net; using Xunit; namespace Tableau.Migration.Tests.Unit.Api @@ -42,7 +45,8 @@ public ApiClientTest() MockSessionProvider.Object, MockLoggerFactory.Object, MockSitesApiClient.Object, - MockSharedResourcesLocalizer.Object); + MockSharedResourcesLocalizer.Object, + Serializer); } } @@ -109,7 +113,7 @@ public async Task Returns_error() request.AssertUri(SiteConnectionConfiguration.ServerUrl, $"/api/{TableauServerVersion.RestApiVersion}/serverinfo"); - MockSessionProvider.Verify(p => p.SetCurrentUserAndSiteAsync(It.IsAny(), Cancel), Times.Never); + MockSessionProvider.Verify(p => p.SetCurrentSessionAsync(It.IsAny(), TableauInstanceType.Unknown, Cancel), Times.Never); } } @@ -120,34 +124,49 @@ public async Task Returns_site_client() { var signInResponse = AutoFixture.CreateResponse(); + var mockResponse = new MockHttpResponseMessage(signInResponse); + var mockSitesResponse = new MockHttpResponseMessage(); + mockSitesResponse.Setup(p => p.StatusCode).Returns(System.Net.HttpStatusCode.OK); + MockHttpClient.SetupResponse(mockResponse); + MockHttpClient.SetupResponse(mockSitesResponse); await using var result = await ApiClient.SignInAsync(Cancel); Assert.True(result.Success); Assert.Same(MockSitesApiClient.Object, result.Value); - var request = MockHttpClient.AssertSingleRequest(); - - request.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/auth/signin"); - - await request.AssertContentAsync( - Serializer, - r => + var requests = MockHttpClient.AssertRequestCount(2); + Assert.Collection(requests, + async signInRequest => { - Assert.Equal(r.Credentials!.Site!.ContentUrl, SiteConnectionConfiguration.SiteContentUrl); - Assert.Equal(r.Credentials.PersonalAccessTokenName, SiteConnectionConfiguration.AccessTokenName); - Assert.Equal(r.Credentials.PersonalAccessTokenSecret, SiteConnectionConfiguration.AccessToken); - }); - - MockSessionProvider.Verify(p => p.SetCurrentUserAndSiteAsync(It.Is(r => - r.SiteId == signInResponse.Item!.Site!.Id && - r.SiteContentUrl == signInResponse.Item.Site.ContentUrl && - r.UserId == signInResponse.Item.User!.Id && - r.Token == signInResponse.Item.Token), Cancel), - Times.Once); + signInRequest.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/auth/signin"); + + await signInRequest.AssertContentAsync( + Serializer, + r => + { + Assert.Equal(r.Credentials!.Site!.ContentUrl, SiteConnectionConfiguration.SiteContentUrl); + Assert.Equal(r.Credentials.PersonalAccessTokenName, SiteConnectionConfiguration.AccessTokenName); + Assert.Equal(r.Credentials.PersonalAccessTokenSecret, SiteConnectionConfiguration.AccessToken); + }); + + MockSessionProvider.Verify(p => p.SetCurrentSessionAsync(It.Is(r => + r.SiteId == signInResponse.Item!.Site!.Id && + r.SiteContentUrl == signInResponse.Item.Site.ContentUrl && + r.UserId == signInResponse.Item.User!.Id && + r.Token == signInResponse.Item.Token), + TableauInstanceType.Server, + Cancel), + Times.Once); + }, + getSitesRequest => + { + getSitesRequest.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/sites"); + } + ); } [Fact] @@ -170,7 +189,7 @@ public async Task Gets_Rest_Api_version_if_not_set() await using var result = await ApiClient.SignInAsync(Cancel); - var requests = MockHttpClient.AssertRequestCount(2); + var requests = MockHttpClient.AssertRequestCount(3); var signInRequest = requests[1]; @@ -197,7 +216,51 @@ public async Task Returns_error() request.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/auth/signin"); } } + public class GetInstanceTypeAsync : ApiClientTest + { + [Theory] + [InlineData(HttpStatusCode.OK, TableauInstanceType.Server)] + [InlineData(HttpStatusCode.Forbidden, TableauInstanceType.Unknown)] + [InlineData(HttpStatusCode.NotFound, TableauInstanceType.Unknown)] + [InlineData(HttpStatusCode.Redirect, TableauInstanceType.Unknown)] + public async Task Returns_correct_instance_type(HttpStatusCode statusCode, TableauInstanceType expectedInstanceType) + { + var mockSitesResponse = new MockHttpResponseMessage(); + mockSitesResponse.Setup(p => p.StatusCode).Returns(statusCode); + + MockHttpClient.SetupResponse(mockSitesResponse); + + var result = await ApiClient.GetInstanceTypeAsync(Cancel); + Assert.Equal(expectedInstanceType, result); + + var request = MockHttpClient.AssertSingleRequest(); + request.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/sites"); + } + [Fact] + public async Task Returns_cloud_instance_type() + { + var mockSitesResponse = new MockHttpResponseMessage(); + var tsResponse = new EmptyTableauServerResponse( + new() { Code = ApiClient.SITES_QUERY_NOT_SUPPORTED, Summary = It.IsAny(), Detail = It.IsAny() }); + + var content = new DefaultHttpResponseMessage( + new HttpResponseMessage(HttpStatusCode.Forbidden) + { + Content = Serializer.Serialize(tsResponse, MediaTypes.Xml) + }); + + Assert.NotNull(content); + MockHttpClient.SetupResponse(content); + + var result = await ApiClient.GetInstanceTypeAsync(Cancel); + + Assert.Equal(TableauInstanceType.Cloud, result); + + var request = MockHttpClient.AssertSingleRequest(); + request.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/sites"); + } + } public class GetCurrentServerSessionAsync : ApiClientTest { [Fact] diff --git a/tests/Tableau.Migration.Tests/Unit/Api/ApiTestBase.cs b/tests/Tableau.Migration.Tests/Unit/Api/ApiTestBase.cs index d38f01b3..9db9dcd2 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/ApiTestBase.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/ApiTestBase.cs @@ -16,7 +16,9 @@ // using System; +using System.Collections.Generic; using System.Net.Http; +using System.Threading; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; @@ -25,9 +27,13 @@ using Tableau.Migration.Api.Publishing; using Tableau.Migration.Api.Rest.Models; using Tableau.Migration.Api.Rest.Models.Responses; +using Tableau.Migration.Api.Rest.Models.Responses.Server; +using Tableau.Migration.Api.Rest.Models.Types; using Tableau.Migration.Api.Tags; using Tableau.Migration.Config; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Net; using Tableau.Migration.Net.Rest; @@ -51,6 +57,11 @@ public abstract class ApiTestBase : AutoFixtureTestBase, IApiClientTestDependenc public Mock MockContentFinderFactory => Dependencies.MockContentFinderFactory; public Mock> MockProjectFinder => Dependencies.MockProjectFinder; public Mock> MockUserFinder => Dependencies.MockUserFinder; + public Mock> MockWorkbookFinder => Dependencies.MockWorkbookFinder; + public Mock> MockDataSourceFinder => Dependencies.MockDataSourceFinder; + public Mock> MockScheduleFinder => Dependencies.MockScheduleFinder; + public Mock MockContentCacheFactory => Dependencies.MockContentCacheFactory; + public Mock> MockScheduleCache => Dependencies.MockScheduleCache; public Mock MockPermissionsClientFactory => Dependencies.MockPermissionsClientFactory; public Mock MockTaskDelayer => Dependencies.MockTaskDelayer; public Mock MockDataSourcePublisher => Dependencies.MockDataSourcePublisher; @@ -118,5 +129,60 @@ protected IHttpResponseMessage SetupSuccessResponse(HttpContent? content = null) protected TService CreateService() where TService : class => ActivatorUtilities.CreateInstance(Dependencies); + + protected void SetupExtractRefreshContentFinder(IExtractRefreshType extractRefresh) + { + var contentType = extractRefresh.GetContentType(); + var contentId = extractRefresh.GetContentId(); + + var contentReference = Create>(m => + { + m.SetupGet(r => r.Id).Returns(contentId); + }) + .Object; + + switch (contentType) + { + case ExtractRefreshContentType.Workbook: + SetupContentFinder(MockWorkbookFinder); + break; + + case ExtractRefreshContentType.DataSource: + SetupContentFinder(MockDataSourceFinder); + break; + + default: + throw new NotSupportedException($"Content type {contentType} is not supported."); + } + + if (extractRefresh is IServerExtractRefreshType serverExtractRefresh) + { + Guard.AgainstNull(serverExtractRefresh.Schedule, () => serverExtractRefresh.Schedule); + + var scheduleId = serverExtractRefresh.Schedule.Id; + + var cachedSchedule = Create>(m => + { + m.SetupGet(s => s.Id).Returns(scheduleId); + }) + .Object; + + var scheduleReference = cachedSchedule.ToStub(); + + MockScheduleFinder.Setup(f => f.FindByIdAsync(scheduleId, It.IsAny())).ReturnsAsync(scheduleReference); + + MockScheduleCache.Setup(f => f.ForIdAsync(scheduleId, It.IsAny())).ReturnsAsync(cachedSchedule); + } + + void SetupContentFinder(Mock> mockFinder) + where T : IContentReference + => mockFinder.Setup(f => f.FindByIdAsync(contentId, It.IsAny())).ReturnsAsync(contentReference); + } + + protected void SetupExtractRefreshContentFinder(IEnumerable extractRefreshes) + { + foreach (var extractRefresh in extractRefreshes) + SetupExtractRefreshContentFinder(extractRefresh); + } } } diff --git a/tests/Tableau.Migration.Tests/Unit/Api/GroupsApiClientTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/GroupsApiClientTests.cs index 738b9855..65f489f5 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/GroupsApiClientTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/GroupsApiClientTests.cs @@ -494,7 +494,7 @@ private void AssertGetGroupRequest(HttpRequestMessage r, string domain, string n public class PublishAsync_Cancellation : GroupsApiClientTest { [Fact] - public async void Publish_cancel_after_create_group() + public async Task Publish_cancel_after_create_group() { var existingGroup = CreateGroup(); @@ -546,7 +546,7 @@ public async void Publish_cancel_after_create_group() } [Fact] - public async void Publish_cancel_during_delete_user_from_group() + public async Task Publish_cancel_during_delete_user_from_group() { var existingGroup = CreateGroup(); @@ -594,7 +594,7 @@ public async void Publish_cancel_during_delete_user_from_group() } [Fact] - public async void Publish_cancel_during_add_user_to_group() + public async Task Publish_cancel_during_add_user_to_group() { var existingGroup = CreateGroup(); diff --git a/tests/Tableau.Migration.Tests/Unit/Api/IApiClientTestDependencies.cs b/tests/Tableau.Migration.Tests/Unit/Api/IApiClientTestDependencies.cs index 20701ed5..9d886860 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/IApiClientTestDependencies.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/IApiClientTestDependencies.cs @@ -22,6 +22,7 @@ using Tableau.Migration.Api.Publishing; using Tableau.Migration.Config; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Net; using Tableau.Migration.Net.Rest; @@ -33,11 +34,16 @@ internal interface IApiClientTestDependencies Mock MockApiClientInput { get; } Mock MockConfigReader { get; } Mock MockContentFinderFactory { get; } + Mock MockContentCacheFactory { get; } + Mock> MockProjectFinder { get; } + Mock> MockUserFinder { get; } + Mock> MockWorkbookFinder { get; } + Mock> MockDataSourceFinder { get; } + Mock> MockScheduleFinder { get; } MockHttpClient MockHttpClient { get; } Mock MockLogger { get; } Mock MockLoggerFactory { get; } Mock MockPermissionsClientFactory { get; } - Mock> MockProjectFinder { get; } Mock MockRequestBuilderInput { get; } Mock MockSessionProvider { get; } MockSharedResourcesLocalizer MockSharedResourcesLocalizer { get; } diff --git a/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs index 63d4380e..86f5b8c8 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs @@ -25,6 +25,7 @@ using Tableau.Migration.Config; using Tableau.Migration.Content; using Tableau.Migration.Content.Files; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Content.Search; using Tableau.Migration.Net; using Xunit; @@ -108,6 +109,7 @@ public async Task RegistersScopedApiClients() AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); + AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); @@ -153,7 +155,7 @@ public void Adds_http_services_if_not_previously_added() } [Fact] - public async void Uses_existing_DefaultPermissionsContentTypeOptions() + public async Task Uses_existing_DefaultPermissionsContentTypeOptions() { var existingOptions = new DefaultPermissionsContentTypeOptions(); @@ -198,6 +200,27 @@ public async Task FileStoreRedirectFromInputAsync() Assert.Same(apiInput.FileStore, contentFileStore); } + + [Fact] + public async Task Registers_content_caches() + { + await using var scope = InitializeApiScope(); + + AssertService(scope, ServiceLifetime.Scoped); + AssertService, ApiContentCache>(scope, ServiceLifetime.Scoped); + AssertService, ApiContentCache>(scope, ServiceLifetime.Scoped); + + var serverScheduleCache = scope.ServiceProvider.GetRequiredService>(); + + var caches = new object[] + { + scope.ServiceProvider.GetRequiredService>(), + scope.ServiceProvider.GetRequiredService>(), + scope.ServiceProvider.GetRequiredService>() + }; + + caches.AssertAllSame(); + } } } } diff --git a/tests/Tableau.Migration.Tests/Unit/Api/ServerSessionProviderTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/ServerSessionProviderTests.cs index b0b09a23..6b260925 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/ServerSessionProviderTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/ServerSessionProviderTests.cs @@ -72,7 +72,7 @@ public async Task SetsUserAndSiteWithSignInResultAsync() { var signInResult = Create(); - await Provider.SetCurrentUserAndSiteAsync(signInResult, Cancel); + await Provider.SetCurrentSessionAsync(signInResult, TableauInstanceType.Server, Cancel); Assert.Equal(signInResult.UserId, Provider.UserId); Assert.Equal(signInResult.SiteContentUrl, Provider.SiteContentUrl); @@ -89,7 +89,7 @@ public async Task SetsUserAndSiteFromValuesAsync() var siteId = Create(); var token = Create(); - await Provider.SetCurrentUserAndSiteAsync(userId, siteId, siteContentUrl, token, Cancel); + await Provider.SetCurrentSessionAsync(userId, siteId, siteContentUrl, token, TableauInstanceType.Cloud, Cancel); Assert.Equal(userId, Provider.UserId); Assert.Equal(siteContentUrl, Provider.SiteContentUrl); @@ -106,13 +106,14 @@ public async Task ClearsUserAsync() { var signInResult = Create(); - await Provider.SetCurrentUserAndSiteAsync(signInResult, Cancel); + await Provider.SetCurrentSessionAsync(signInResult, TableauInstanceType.Server, Cancel); - await Provider.ClearCurrentUserAndSiteAsync(Cancel); + await Provider.ClearCurrentSessionAsync(Cancel); Assert.Null(Provider.UserId); Assert.Null(Provider.SiteContentUrl); Assert.Null(Provider.SiteId); + Assert.Equal(TableauInstanceType.Unknown, Provider.InstanceType); MockTokenProvider.Verify(p => p.ClearAsync(Cancel), Times.Once); } diff --git a/tests/Tableau.Migration.Tests/Unit/Api/Simulation/TableauApiSimulatorFactoryTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/Simulation/TableauApiSimulatorFactoryTests.cs index 2c213042..1946327b 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/Simulation/TableauApiSimulatorFactoryTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/Simulation/TableauApiSimulatorFactoryTests.cs @@ -59,8 +59,8 @@ public void NoReCreation() { var factory = CreateFactory(); - var simulator1 = factory.GetOrCreate(new("http://localhost")); - var simulator2 = factory.GetOrCreate(new("http://localhost")); + var simulator1 = factory.GetOrCreate(new("http://localhost"), true); + var simulator2 = factory.GetOrCreate(new("http://localhost"), true); Assert.Same(simulator1, simulator2); MockSimulatorCollection.Verify(x => x.AddOrUpdate(It.IsAny()), Times.Once); @@ -71,7 +71,7 @@ public void CreatesAuthenticationUser() { var factory = CreateFactory(); - var simulator = factory.GetOrCreate(new("http://localhost")); + var simulator = factory.GetOrCreate(new("http://localhost"), true); MockSimulatorCollection.Verify(x => x.AddOrUpdate(simulator), Times.Once); diff --git a/tests/Tableau.Migration.Tests/Unit/Api/SitesApiClientTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/SitesApiClientTests.cs index e15866eb..7477fa15 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/SitesApiClientTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/SitesApiClientTests.cs @@ -215,7 +215,7 @@ public async Task Returns_success() request.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/auth/signout"); - MockSessionProvider.Verify(p => p.ClearCurrentUserAndSiteAsync(Cancel), Times.Once); + MockSessionProvider.Verify(p => p.ClearCurrentSessionAsync(Cancel), Times.Once); } [Fact] @@ -238,7 +238,7 @@ public async Task Returns_failure() request.AssertRelativeUri($"/api/{TableauServerVersion.RestApiVersion}/auth/signout"); - MockSessionProvider.Verify(p => p.ClearCurrentUserAndSiteAsync(Cancel), Times.Once); + MockSessionProvider.Verify(p => p.ClearCurrentSessionAsync(Cancel), Times.Once); } [Fact] diff --git a/tests/Tableau.Migration.Tests/Unit/Config/ConfigurationTests.cs b/tests/Tableau.Migration.Tests/Unit/Config/ConfigurationTests.cs index 096f5463..b151bd68 100644 --- a/tests/Tableau.Migration.Tests/Unit/Config/ConfigurationTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Config/ConfigurationTests.cs @@ -31,7 +31,7 @@ using Tableau.Migration.Config; using Tableau.Migration.Content; using Tableau.Migration.Content.Permissions; -using Tableau.Migration.Engine.Pipelines; +using Tableau.Migration.Content.Schedules.Server; using Xunit; using Xunit.Abstractions; @@ -72,6 +72,10 @@ public class ConfigurationTests {{ ""type"":""DataSource"", ""batchSize"": {TestData.DATASOURCE_BATCH_SIZE} + }}, + {{ + ""type"":""ServerExtractRefreshTask"", + ""batchSize"": {TestData.EXTRACT_REFRESH_TASK_BATCHSIZE} }} ], ""Network"": {{ @@ -130,6 +134,7 @@ protected class TestData public const int PROJECT_BATCH_SIZE = 203; public const int WORKBOOK_BATCH_SIZE = 204; public const int DATASOURCE_BATCH_SIZE = 205; + public const int EXTRACT_REFRESH_TASK_BATCHSIZE = 12; public const int FILE_CHUNK_SIZE_GB = 2034; } @@ -237,6 +242,7 @@ public void LoadFromInitialConfiguration() Assert.Equal(TestData.PROJECT_BATCH_SIZE, configReader.Get().BatchSize); Assert.Equal(TestData.WORKBOOK_BATCH_SIZE, configReader.Get().BatchSize); Assert.Equal(TestData.DATASOURCE_BATCH_SIZE, configReader.Get().BatchSize); + Assert.Equal(TestData.EXTRACT_REFRESH_TASK_BATCHSIZE, configReader.Get().BatchSize); var freshConfig = configReader.Get(); @@ -320,6 +326,7 @@ public void DefaultsApplied() Assert.Equal(ContentTypesOptions.Defaults.BATCH_SIZE, configReader.Get().BatchSize); Assert.Equal(ContentTypesOptions.Defaults.BATCH_SIZE, configReader.Get().BatchSize); + Assert.Equal(ContentTypesOptions.Defaults.BATCH_SIZE, configReader.Get ().BatchSize); Assert.NotNull(freshConfig?.DefaultPermissionsContentTypes); } diff --git a/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentFileStreamTests.cs b/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentFileStreamTests.cs index 9ac3c8e9..2ed512e5 100644 --- a/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentFileStreamTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentFileStreamTests.cs @@ -46,7 +46,7 @@ public override ValueTask DisposeAsync() public class Ctor { [Fact] - public async void Initializes() + public async Task Initializes() { var stream = new MemoryStream(); await using var fileStream = new ContentFileStream(stream); @@ -58,7 +58,7 @@ public async void Initializes() public class DisposeAsync { [Fact] - public async void DisposesStream() + public async Task DisposesStream() { var stream = new TestStream(); var fileStream = new ContentFileStream(stream); diff --git a/tests/Tableau.Migration.Tests/Unit/Content/Files/SeekableCryptoStreamTests.cs b/tests/Tableau.Migration.Tests/Unit/Content/Files/SeekableCryptoStreamTests.cs index a3ac3b29..6792a0dc 100644 --- a/tests/Tableau.Migration.Tests/Unit/Content/Files/SeekableCryptoStreamTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Content/Files/SeekableCryptoStreamTests.cs @@ -143,7 +143,7 @@ public async Task Does_not_dispose_inner_stream_when_leaveOpen_is_true(CryptoStr [Theory] [Values(true, false)] - public async void Respects_leaveOpen_flag(bool leaveOpen) + public async Task Respects_leaveOpen_flag(bool leaveOpen) { var mode = Create(); diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationCacheTest.cs b/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationCacheTest.cs index 5f5b7eac..4e4ae347 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationCacheTest.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationCacheTest.cs @@ -16,13 +16,9 @@ // using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; -using System.Threading; using AutoFixture; using Moq; -using Tableau.Migration.Api; -using Tableau.Migration.Config; using Tableau.Migration.Content; using Tableau.Migration.Engine.Endpoints; using Tableau.Migration.Engine.Endpoints.Search; @@ -30,29 +26,18 @@ namespace Tableau.Migration.Tests.Unit.Engine.Endpoints.Search { - public abstract class BulkDestinationCacheTest : AutoFixtureTestBase + public abstract class BulkDestinationCacheTest : BulkCacheTest where TCache : BulkDestinationCache where TContent : class, IContentReference { protected readonly Mock MockManifestEntryBuilder; protected readonly Mock MockManifestPartition; protected readonly Mock MockDestinationEndpoint; - protected readonly Mock MockSitesApiClient; - protected readonly Mock> MockListApiClient; - - protected readonly TCache Cache; - - protected ContentTypesOptions ContentTypesOptions { get; set; } = new ContentTypesOptions(); - - protected List EndpointContent { get; set; } protected Dictionary> MockManifestEntries = new(); public BulkDestinationCacheTest() { - EndpointContent = CreateMany().ToList(); - ContentTypesOptions.BatchSize = EndpointContent.Count / 2; - MockManifestEntryBuilder = Freeze>(); SyncManifestEntries(); @@ -68,25 +53,11 @@ public BulkDestinationCacheTest() mockManifestEditor.Setup(x => x.Entries.GetOrCreatePartition()) .Returns(MockManifestPartition.Object); - MockListApiClient = Freeze>>(); - MockListApiClient.Setup(x => x.GetAllAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(() => Result>.Succeeded(EndpointContent.ToImmutableList())); - - MockSitesApiClient = Freeze>(); - MockSitesApiClient.Setup(x => x.GetListApiClient()) - .Returns(MockListApiClient.Object); - MockDestinationEndpoint = Freeze>(); MockDestinationEndpoint.Setup(x => x.SiteApi) .Returns(MockSitesApiClient.Object); AutoFixture.Register(() => MockDestinationEndpoint.Object); - - var mockConfigReader = Freeze>(); - mockConfigReader.Setup(x => x.Get()) - .Returns(() => ContentTypesOptions); - - Cache = Create(); } protected void SyncManifestEntries() @@ -103,4 +74,8 @@ protected void SyncManifestEntries() .ToDictionary(m => m.Object.MappedLocation); } } + + public abstract class BulkDestinationCacheTest : BulkDestinationCacheTest, TContent> + where TContent : class, IContentReference + { } } diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationProjectCacheTests.cs b/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationProjectCacheTests.cs index 2fc4ae87..da63ac6f 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationProjectCacheTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/BulkDestinationProjectCacheTests.cs @@ -22,7 +22,6 @@ using Tableau.Migration.Api.Rest.Models; using Tableau.Migration.Content; using Tableau.Migration.Engine.Endpoints.Search; -using Tableau.Migration.Paging; using Xunit; namespace Tableau.Migration.Tests.Unit.Engine.Endpoints.Search diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/IServiceCollectionExtensionsTests.cs b/tests/Tableau.Migration.Tests/Unit/Engine/IServiceCollectionExtensionsTests.cs index 45f98e2a..5d77b2c8 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/IServiceCollectionExtensionsTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/IServiceCollectionExtensionsTests.cs @@ -241,6 +241,14 @@ public async Task RegistersScopedEndpointPreparerAsync() AssertService>(scope, ServiceLifetime.Scoped); } + [Fact] + public async Task RegistersScopedExtractRefreshTaskServerToCloudPreparerAsync() + { + await using var scope = await InitializeMigrationScopeAsync(); + + AssertService(scope, ServiceLifetime.Scoped); + } + [Fact] public async Task RegistersScopedItemBatchMigratorAsync() { diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/MigrationPlanBuilderTests.cs b/tests/Tableau.Migration.Tests/Unit/Engine/MigrationPlanBuilderTests.cs index b522f886..3e97667c 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/MigrationPlanBuilderTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/MigrationPlanBuilderTests.cs @@ -19,20 +19,21 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using AutoFixture; -using Microsoft.Extensions.Logging; using Moq; using Tableau.Migration.Api.Simulation; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; using Tableau.Migration.Engine; using Tableau.Migration.Engine.Endpoints; using Tableau.Migration.Engine.Hooks; using Tableau.Migration.Engine.Hooks.Filters; using Tableau.Migration.Engine.Hooks.Filters.Default; using Tableau.Migration.Engine.Hooks.Mappings; +using Tableau.Migration.Engine.Hooks.PostPublish.Default; using Tableau.Migration.Engine.Hooks.Transformers; using Tableau.Migration.Engine.Hooks.Transformers.Default; using Tableau.Migration.Engine.Options; -using Tableau.Migration.Engine.Pipelines; using Xunit; namespace Tableau.Migration.Tests.Unit.Engine @@ -51,7 +52,7 @@ public class MigrationPlanBuilderTest : AutoFixtureTestBase public MigrationPlanBuilderTest() { MockOptionsBuilder = Create>(); - MockHookBuilder = Create>(); + MockHookBuilder = new() { CallBase = true }; MockMappingBuilder = new() { CallBase = true }; MockFilterBuilder = new() { CallBase = true }; MockTransformerBuilder = new() { CallBase = true }; @@ -77,16 +78,23 @@ protected void AssertExtensionsCleared() protected void AssertDefaultExtensions() { //Add expected default extensions to assert for here. - - Assert.All(PipelineProfile.ServerToCloud.GetSupportedContentTypes(), - ct => MockFilterBuilder.Verify(b => b.Add(typeof(PreviouslyMigratedFilter<>), It.IsAny>()), Times.Once)); - + MockFilterBuilder.Verify(b => b.Add(typeof(PreviouslyMigratedFilter<>), It.IsAny>()), Times.Once); MockFilterBuilder.Verify(b => b.Add(It.IsAny>()), Times.Once); MockFilterBuilder.Verify(b => b.Add(typeof(SystemOwnershipFilter<>), It.IsAny>()), Times.Once); MockTransformerBuilder.Verify(x => x.Add(It.IsAny>()), Times.Once); MockTransformerBuilder.Verify(x => x.Add(It.IsAny>()), Times.Once); + MockTransformerBuilder.Verify(x => x.Add(typeof(OwnershipTransformer<>), It.IsAny>()), Times.Once); MockTransformerBuilder.Verify(x => x.Add(It.IsAny>()), Times.Once); + MockTransformerBuilder.Verify(x => x.Add(It.IsAny>()), Times.Once); + MockTransformerBuilder.Verify(x => x.Add(It.IsAny>()), Times.Once); + MockTransformerBuilder.Verify(x => x.Add(typeof(CloudScheduleCompatibilityTransformer<>), It.IsAny>()), Times.Once); + + MockHookBuilder.Verify(x => x.Add(typeof(OwnerItemPostPublishHook<,>), It.IsAny>()), Times.Once); + MockHookBuilder.Verify(x => x.Add(typeof(PermissionsItemPostPublishHook<,>), It.IsAny>()), Times.Once); + MockHookBuilder.Verify(x => x.Add(typeof(ChildItemsPermissionsPostPublishHook<,>), It.IsAny>()), Times.Once); + MockHookBuilder.Verify(x => x.Add(typeof(TagItemPostPublishHook<,>), It.IsAny>()), Times.Once); + MockHookBuilder.Verify(x => x.Add(It.IsAny>()), Times.Once); } protected void AssertDefaultServerToCloudExtensions() diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineBaseTests.cs b/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineBaseTests.cs index 0e1e6f83..a9a879e1 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineBaseTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineBaseTests.cs @@ -17,6 +17,9 @@ using Moq; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Cloud; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Engine.Actions; using Tableau.Migration.Engine.Endpoints.Search; using Tableau.Migration.Engine.Migrators; @@ -127,6 +130,24 @@ public void CreatesDefaultSourceItemPreparer() Assert.IsType>(migrator); MockServices.Verify(x => x.GetService(typeof(SourceContentItemPreparer)), Times.Once); } + + [Fact] + public void CreatesEndpointItemPreparer() + { + var migrator = Pipeline.GetItemPreparer(); + + Assert.IsType>(migrator); + MockServices.Verify(x => x.GetService(typeof(EndpointContentItemPreparer)), Times.Once); + } + + [Fact] + public void CreatesExtractRefreshTaskServerToCloudPreparer() + { + var migrator = Pipeline.GetItemPreparer(); + + Assert.IsType(migrator); + MockServices.Verify(x => x.GetService(typeof(ExtractRefreshTaskServerToCloudPreparer)), Times.Once); + } } #endregion diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineContentTypeTests.cs b/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineContentTypeTests.cs index 0fbe7468..d2239d44 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineContentTypeTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/MigrationPipelineContentTypeTests.cs @@ -173,10 +173,26 @@ public void Returns_config_keys() { var pipelineContentTypes = ServerToCloudMigrationPipeline.ContentTypes; - foreach(var pipelineContentType in pipelineContentTypes) + foreach (var pipelineContentType in pipelineContentTypes) { Assert.NotNull(pipelineContentType); - Assert.Equal(pipelineContentType.ContentType.Name, $"I{pipelineContentType.GetConfigKey()}"); + var actualConfigKey = pipelineContentType.GetConfigKey(); + + var contentType = pipelineContentType.ContentType; + + if (contentType.GenericTypeArguments.Length == 0) + { + Assert.Equal(contentType.Name, $"I{actualConfigKey}"); + return; + } + + var cleanedTypeName = contentType.Name.TrimEnd('1').TrimEnd('`'); + Assert.StartsWith(cleanedTypeName, $"I{actualConfigKey}"); + + foreach (var arg in contentType.GenericTypeArguments) + { + Assert.Contains($"_{arg.Name.TrimStart('I')}", actualConfigKey); + } } } } diff --git a/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/ServerToCloudMigrationPipelineTests.cs b/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/ServerToCloudMigrationPipelineTests.cs index 4742a5e6..747e8151 100644 --- a/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/ServerToCloudMigrationPipelineTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Engine/Pipelines/ServerToCloudMigrationPipelineTests.cs @@ -22,6 +22,8 @@ using Moq; using Tableau.Migration.Config; using Tableau.Migration.Content; +using Tableau.Migration.Content.Schedules; +using Tableau.Migration.Content.Schedules.Server; using Tableau.Migration.Engine.Actions; using Tableau.Migration.Engine.Migrators.Batch; using Tableau.Migration.Engine.Pipelines; @@ -90,13 +92,14 @@ public void BuildsPipeline() { var actions = Pipeline.BuildActions(); - Assert.Equal(6, actions.Length); + Assert.Equal(7, actions.Length); Assert.IsType(actions[0]); Assert.IsType>(actions[1]); Assert.IsType>(actions[2]); Assert.IsType>(actions[3]); Assert.IsType>(actions[4]); Assert.IsType>(actions[5]); + Assert.IsType>(actions[6]); } [Fact] diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Filters/ISyncContentFilterTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Filters/ISyncContentFilterTests.cs deleted file mode 100644 index 9d378053..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Filters/ISyncContentFilterTests.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Collections.Generic; -using System.Threading.Tasks; -using Moq; -using Tableau.Migration.Content; -using Tableau.Migration.Engine; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Interop.Hooks.Filters; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks.Filters -{ - public class ISyncContentFilterTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncContentFilter - { - public virtual IEnumerable>? Execute(IEnumerable> ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create>>(); - - var result = await ((IMigrationHook>>)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentMappingTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentMappingTests.cs deleted file mode 100644 index d1b6bcc6..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentMappingTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using Moq; -using Tableau.Migration.Engine.Actions; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Interop.Hooks; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks -{ - public class ISyncContentMappingTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncMigrationActionCompletedHook - { - public virtual IMigrationActionResult? Execute(IMigrationActionResult ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create(); - - var result = await ((IMigrationHook)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentTransformerTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentTransformerTests.cs deleted file mode 100644 index 272acf86..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/ISyncContentTransformerTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using Moq; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Interop.Hooks; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks -{ - public class ISyncContentTransformerTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncMigrationHook - { - public virtual string? Execute(string ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create(); - - var result = await ((IMigrationHook)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Mappings/ISyncContentMappingTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Mappings/ISyncContentMappingTests.cs deleted file mode 100644 index 4aa9f076..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Mappings/ISyncContentMappingTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using Moq; -using Tableau.Migration.Content; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Engine.Hooks.Mappings; -using Tableau.Migration.Interop.Hooks.Mappings; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks.Mappings -{ - public class ISyncContentMappingTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncContentMapping - { - public virtual ContentMappingContext? Execute(ContentMappingContext ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create>(); - - var result = await ((IMigrationHook>)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncBulkPostPublishHookTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncBulkPostPublishHookTests.cs deleted file mode 100644 index a149e8f8..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncBulkPostPublishHookTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using Moq; -using Tableau.Migration.Content; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Engine.Hooks.PostPublish; -using Tableau.Migration.Interop.Hooks.PostPublish; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks.PostPublish -{ - public class ISyncBulkPostPublishHookTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncBulkPostPublishHook - { - public virtual BulkPostPublishContext? Execute(BulkPostPublishContext ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create>(); - - var result = await ((IMigrationHook>)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHookTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHookTests.cs deleted file mode 100644 index a2b3a892..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/PostPublish/ISyncContentItemPostPublishHookTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using Moq; -using Tableau.Migration.Content; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Engine.Hooks.PostPublish; -using Tableau.Migration.Interop.Hooks.PostPublish; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks.PostPublish -{ - public class ISyncContentItemPostPublishHookTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncContentItemPostPublishHook - { - public virtual ContentItemPostPublishContext? Execute(ContentItemPostPublishContext ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create>(); - - var result = await ((IMigrationHook>)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncContentTransformerTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncContentTransformerTests.cs deleted file mode 100644 index 39e490c7..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncContentTransformerTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using Moq; -using Tableau.Migration.Content; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Interop.Hooks.Transformers; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks.Transformers -{ - public class ISyncContentTransformerTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncContentTransformer - { - public virtual IUser? Execute(IUser ctx) => ctx; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var ctx = Create(); - - var result = await ((IMigrationHook)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockTransformer.Verify(x => x.Execute(ctx), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncXmlContentTransformerTests.cs b/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncXmlContentTransformerTests.cs deleted file mode 100644 index 9dae8658..00000000 --- a/tests/Tableau.Migration.Tests/Unit/Interop/Hooks/Transformers/ISyncXmlContentTransformerTests.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2024, Salesforce, Inc. -// SPDX-License-Identifier: Apache-2 -// -// 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.Threading.Tasks; -using System.Xml.Linq; -using Moq; -using Tableau.Migration.Content.Files; -using Tableau.Migration.Engine.Hooks; -using Tableau.Migration.Interop.Hooks.Transformers; -using Xunit; - -namespace Tableau.Migration.Tests.Unit.Interop.Hooks.Transformers -{ - public class ISyncXmlContentTransformerTests - { - public class ExecuteAsync : AutoFixtureTestBase - { - public class TestImplementation : ISyncXmlContentTransformer - { - public virtual void Transform(TestFileContentType ctx, XDocument xml) { } - - public virtual bool NeedsXmlTransforming(TestFileContentType ctx) => true; - } - - [Fact] - public async Task CallsExecuteAsync() - { - var mockTransformer = new Mock() - { - CallBase = true - }; - - var mockFile = Freeze>(); - var ctx = Create(); - - var mockXmlStream = Freeze>(); - var xml = Freeze(); - - var result = await ((IMigrationHook)mockTransformer.Object).ExecuteAsync(ctx, Cancel); - - Assert.Same(ctx, result); - - mockFile.Verify(x => x.GetXmlStreamAsync(Cancel), Times.Once); - mockXmlStream.Verify(x => x.GetXmlAsync(Cancel), Times.Once); - - mockTransformer.Verify(x => x.Transform(ctx, xml), Times.Once); - } - } - } -} diff --git a/tests/Tableau.Migration.Tests/Unit/Net/HttpContentRequestBuilderTests.cs b/tests/Tableau.Migration.Tests/Unit/Net/HttpContentRequestBuilderTests.cs index db5a5b3c..ddaf095b 100644 --- a/tests/Tableau.Migration.Tests/Unit/Net/HttpContentRequestBuilderTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Net/HttpContentRequestBuilderTests.cs @@ -19,6 +19,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; +using System.Threading.Tasks; using Moq; using Tableau.Migration.Net; using Xunit; @@ -125,7 +126,7 @@ public void Sets_content() } [Fact] - public async void Sets_string_content() + public async Task Sets_string_content() { var content = @"{ ""id"": ""1234"" }"; @@ -161,7 +162,7 @@ public void Sets_content() } [Fact] - public async void Sets_string_content() + public async Task Sets_string_content() { var content = @"";