diff --git a/Directory.Build.props b/Directory.Build.props index f6f2b08..5e366d6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,7 +9,7 @@ false CS0105;CS0108;CS0109;CS0114;CS0162;CS0168;CS0169;CS0219;CS0252;CS0414;CS0472;CS0649;CS0652;CS1717;CS1998;CS4014;xUnit1013;MSB3245;MSB3270,NU1602 $(NoWarn);NU5105 prompt @@ -19,7 +19,7 @@ $([System.Text.RegularExpressions.Regex]::Match($(Version), '\d+\.\d+').Value) $([System.Text.RegularExpressions.Regex]::Match($(Version), '\d+\.\d+.\d+').Value) CluedIn ApS - Copyright (c) 2020 $(Company). All rights reserved. + Copyright (c) 2021 $(Company). All rights reserved. CluedIn $(MSBuildProjectName) $(Product).$(AssemblyTitle) diff --git a/Directory.Build.targets b/Directory.Build.targets index 1b26f1b..8773bf2 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -18,4 +18,4 @@ - + \ No newline at end of file diff --git a/ExternalSearch.Providers.VatLayer.sln b/ExternalSearch.Providers.VatLayer.sln index d3ae654..4df3e39 100644 --- a/ExternalSearch.Providers.VatLayer.sln +++ b/ExternalSearch.Providers.VatLayer.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29503.13 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B2A52533-7FBF-41FE-A0AF-874FC54300B2}" EndProject @@ -46,22 +46,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Git", "Git", "{17EE3C8D-BAE .gitignore = .gitignore EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalSearch.Providers.VatLayer", "src\ExternalSearch.Providers.VatLayer.csproj", "{BD49FBC7-7E7B-410C-BBB4-F3B0E3293541}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalSearch.VatLayer.Integration.Tests", "test\integration\ExternalSearch.VatLayer.Integration.Tests\ExternalSearch.VatLayer.Integration.Tests.csproj", "{DD79FB4E-FB22-41D7-8544-E2947EE6E99C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalSearch.VatLayer.Unit.Tests", "test\unit\ExternalSearch.VatLayer.Unit.Tests\ExternalSearch.VatLayer.Unit.Tests.csproj", "{195D0932-EA29-40BF-BBCE-26F7906504B9}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalSearch.Providers.VatLayer", "src\ExternalSearch.Providers.VatLayer\ExternalSearch.Providers.VatLayer.csproj", "{9FD65D12-0D5B-46B7-AE96-1502E4A45E30}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Provider.ExternalSearch.Providers.VatLayer", "src\ExternalSearch.Providers.VatLayer.Provider\Provider.ExternalSearch.Providers.VatLayer.csproj", "{D2B36432-79F7-41AD-90A8-CF34F2E07A33}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BD49FBC7-7E7B-410C-BBB4-F3B0E3293541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BD49FBC7-7E7B-410C-BBB4-F3B0E3293541}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BD49FBC7-7E7B-410C-BBB4-F3B0E3293541}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BD49FBC7-7E7B-410C-BBB4-F3B0E3293541}.Release|Any CPU.Build.0 = Release|Any CPU {DD79FB4E-FB22-41D7-8544-E2947EE6E99C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD79FB4E-FB22-41D7-8544-E2947EE6E99C}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD79FB4E-FB22-41D7-8544-E2947EE6E99C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -70,6 +68,14 @@ Global {195D0932-EA29-40BF-BBCE-26F7906504B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {195D0932-EA29-40BF-BBCE-26F7906504B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {195D0932-EA29-40BF-BBCE-26F7906504B9}.Release|Any CPU.Build.0 = Release|Any CPU + {9FD65D12-0D5B-46B7-AE96-1502E4A45E30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FD65D12-0D5B-46B7-AE96-1502E4A45E30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FD65D12-0D5B-46B7-AE96-1502E4A45E30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FD65D12-0D5B-46B7-AE96-1502E4A45E30}.Release|Any CPU.Build.0 = Release|Any CPU + {D2B36432-79F7-41AD-90A8-CF34F2E07A33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2B36432-79F7-41AD-90A8-CF34F2E07A33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2B36432-79F7-41AD-90A8-CF34F2E07A33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2B36432-79F7-41AD-90A8-CF34F2E07A33}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -82,9 +88,10 @@ Global {02641789-0D38-4DBB-9288-23592CF55D25} = {9BD54E81-D9C8-4419-82B8-8EE6CC7E2647} {2C3AECCF-DCB5-4ED7-8B7B-8F373EDE3A5E} = {9BD54E81-D9C8-4419-82B8-8EE6CC7E2647} {17EE3C8D-BAE4-481A-B9CC-1BE878E86124} = {9BD54E81-D9C8-4419-82B8-8EE6CC7E2647} - {BD49FBC7-7E7B-410C-BBB4-F3B0E3293541} = {B2A52533-7FBF-41FE-A0AF-874FC54300B2} {DD79FB4E-FB22-41D7-8544-E2947EE6E99C} = {DBD1964B-DBD9-4C70-96CA-391C34B3D75F} {195D0932-EA29-40BF-BBCE-26F7906504B9} = {A32B6852-82C7-4107-8C68-AE9232289E09} + {9FD65D12-0D5B-46B7-AE96-1502E4A45E30} = {B2A52533-7FBF-41FE-A0AF-874FC54300B2} + {D2B36432-79F7-41AD-90A8-CF34F2E07A33} = {B2A52533-7FBF-41FE-A0AF-874FC54300B2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6A61CB42-80C5-4A83-AC3E-DA41FC875525} diff --git a/GitVersion.yml b/GitVersion.yml index fda7acc..c0938e8 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,10 +1,6 @@ -mode: ContinuousDeployment -next-version: 3.2 -branches: - master: - mode: ContinuousDelivery - pull-request: - tag: pr - increment: None - develop: - tag: alpha1 \ No newline at end of file +# GitVersion.yml +mode: ContinuousDelivery +next-version: 3.3 +branches: {} +ignore: + sha: [] \ No newline at end of file diff --git a/Packages.props b/Packages.props index 3947b4b..dcd45c5 100644 --- a/Packages.props +++ b/Packages.props @@ -1,9 +1,9 @@ + <_ComponentHost>2.0.0 <_AutoFixture>4.11.0 - <_CluedIn>3.2.0-* + <_CluedIn>3.3.0-* - - - + + - + - - - + \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e5b3af5..1d675d8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -38,14 +38,7 @@ variables: steps: - # Configure NuGet -- pwsh: | - @('develop','release','AzurePipelines') | ForEach-Object{ - dotnet nuget update source $_ -p $env:NUGET_KEY -u VssSessionToken --configfile nuget.config - } - condition: and(succeeded(), variables['nuget.key']) - displayName: 'Add api token to access nuget artifacts' - env: - NUGET_KEY: $(nuget.key) +- task: NuGetAuthenticate@0 + displayName: 'Authenticate with nuget' - template: crawler.build.yml@templates diff --git a/docs/3.3.0-release-notes.md b/docs/3.3.0-release-notes.md new file mode 100644 index 0000000..6231292 --- /dev/null +++ b/docs/3.3.0-release-notes.md @@ -0,0 +1,2 @@ +### Features +- Implemented Provider Model \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index ba1dd70..0000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - - false - - - - - - git - true - - - symbols.nupkg - true - - - - diff --git a/src/ExternalSearch.Providers.VatLayer.Provider/Provider.ExternalSearch.Providers.VatLayer.csproj b/src/ExternalSearch.Providers.VatLayer.Provider/Provider.ExternalSearch.Providers.VatLayer.csproj new file mode 100644 index 0000000..b93e7e7 --- /dev/null +++ b/src/ExternalSearch.Providers.VatLayer.Provider/Provider.ExternalSearch.Providers.VatLayer.csproj @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/ExternalSearch.Providers.VatLayer.Provider/VatLayerProviderProviderComponent.cs b/src/ExternalSearch.Providers.VatLayer.Provider/VatLayerProviderProviderComponent.cs new file mode 100644 index 0000000..6c01508 --- /dev/null +++ b/src/ExternalSearch.Providers.VatLayer.Provider/VatLayerProviderProviderComponent.cs @@ -0,0 +1,51 @@ +using System.Reflection; +using Castle.MicroKernel.Registration; +using CluedIn.Core; +using CluedIn.Core.Providers; +using CluedIn.Core.Server; +using ComponentHost; +using Constants = CluedIn.ExternalSearch.Providers.VatLayer.Constants; + +namespace CluedIn.Provider.VatLayer +{ + [Component(Constants.ComponentName, "Providers", ComponentType.Service, ServerComponents.ProviderWebApi, Components.Server, Components.DataStores, Isolation = ComponentIsolation.NotIsolated)] + public sealed class VatLayerProviderProviderComponent : ServiceApplicationComponent + { + /********************************************************************************************************** + * CONSTRUCTOR + **********************************************************************************************************/ + + /// + /// Initializes a new instance of the class. + /// + /// The component information. + public VatLayerProviderProviderComponent(ComponentInfo componentInfo) : base(componentInfo) + { + // Dev. Note: Potential for compiler warning here ... CA2214: Do not call overridable methods in constructors + // this class has been sealed to prevent the CA2214 waring being raised by the compiler + Container.Register(Component.For().Instance(this)); + } + + /********************************************************************************************************** + * METHODS + **********************************************************************************************************/ + + /// Starts this instance. + public override void Start() + { + var asm = Assembly.GetAssembly(typeof(VatLayerProviderProviderComponent)); + Container.Register(Types.FromAssembly(asm).BasedOn().WithServiceFromInterface().If(t => !t.IsAbstract).LifestyleSingleton()); + + State = ServiceState.Started; + } + + /// Stops this instance. + public override void Stop() + { + if (State == ServiceState.Stopped) + return; + + State = ServiceState.Stopped; + } + } +} diff --git a/src/ExternalSearch.Providers.VatLayer.Provider/VatLayerSearchProviderProvider.cs b/src/ExternalSearch.Providers.VatLayer.Provider/VatLayerSearchProviderProvider.cs new file mode 100644 index 0000000..c6d1cdf --- /dev/null +++ b/src/ExternalSearch.Providers.VatLayer.Provider/VatLayerSearchProviderProvider.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CluedIn.Core; +using CluedIn.Core.Crawling; +using CluedIn.Core.Data.Relational; +using CluedIn.Core.ExternalSearch; +using CluedIn.Core.Providers; +using CluedIn.Core.Webhooks; +using CluedIn.ExternalSearch; +using CluedIn.ExternalSearch.Providers.VatLayer; +using CluedIn.Providers.Models; +using Constants = CluedIn.ExternalSearch.Providers.VatLayer.Constants; + +namespace CluedIn.Provider.VatLayer +{ + public class VatLayerSearchProviderProvider : ProviderBase, IExtendedProviderMetadata, IExternalSearchProviderProvider + { + public IExternalSearchProvider ExternalSearchProvider { get; } + + public VatLayerSearchProviderProvider([System.Diagnostics.CodeAnalysis.NotNull] ApplicationContext appContext) : base(appContext, GetMetaData()) + { + ExternalSearchProvider = appContext.Container.ResolveAll().Single(n => n.Id == Constants.ProviderId); + } + + private static IProviderMetadata GetMetaData() + { + return new ProviderMetadata + { + Id = Constants.ProviderId, + Name = Constants.ProviderName, + ComponentName = Constants.ComponentName, + AuthTypes = new List(), + SupportsConfiguration = true, + SupportsAutomaticWebhookCreation = false, + SupportsWebHooks = false, + Type = "Enricher" + }; + } + + public override async Task GetCrawlJobData(ProviderUpdateContext context, IDictionary configuration, Guid organizationId, Guid userId, Guid providerDefinitionId) + { + if (configuration == null) + throw new ArgumentNullException(nameof(configuration)); + + var result = new VatLayerExternalSearchJobData(configuration); + + return await Task.FromResult(result); + } + + public override Task TestAuthentication(ProviderUpdateContext context, IDictionary configuration, Guid organizationId, Guid userId, Guid providerDefinitionId) + { + return Task.FromResult(true); + } + + public override Task FetchUnSyncedEntityStatistics(Core.ExecutionContext context, IDictionary configuration, Guid organizationId, Guid userId, Guid providerDefinitionId) + { + throw new NotImplementedException(); + } + + + public override async Task> GetHelperConfiguration(ProviderUpdateContext context, CrawlJobData jobData, Guid organizationId, Guid userId, Guid providerDefinitionId) + { + if (jobData is VatLayerExternalSearchJobData result) + { + return await Task.FromResult(result.ToDictionary()); + } + + throw new InvalidOperationException($"Unexpected data type for {nameof(VatLayerExternalSearchJobData)}, {jobData.GetType()}"); + } + + public override Task> GetHelperConfiguration(ProviderUpdateContext context, CrawlJobData jobData, Guid organizationId, Guid userId, Guid providerDefinitionId, string folderId) + { + return GetHelperConfiguration(context, jobData, organizationId, userId, providerDefinitionId); + } + + public override Task GetAccountInformation(Core.ExecutionContext context, CrawlJobData jobData, Guid organizationId, Guid userId, Guid providerDefinitionId) + { + return Task.FromResult(new AccountInformation(providerDefinitionId.ToString(), providerDefinitionId.ToString())); + } + + public override string Schedule(DateTimeOffset relativeDateTime, bool webHooksEnabled) + { + return $"{relativeDateTime.Minute} 0/23 * * *"; + } + + public override Task> CreateWebHook(Core.ExecutionContext context, CrawlJobData jobData, IWebhookDefinition webhookDefinition, IDictionary config) + { + throw new NotImplementedException(); + } + + public override Task> GetWebHooks(Core.ExecutionContext context) + { + throw new NotImplementedException(); + } + + public override Task DeleteWebHook(Core.ExecutionContext context, CrawlJobData jobData, IWebhookDefinition webhookDefinition) + { + throw new NotImplementedException(); + } + + public override Task GetRemainingApiAllowance(Core.ExecutionContext context, CrawlJobData jobData, Guid organizationId, Guid userId, Guid providerDefinitionId) + { + if (jobData == null) throw new ArgumentNullException(nameof(jobData)); + return Task.FromResult(new CrawlLimit(-1, TimeSpan.Zero)); + } + + public override IEnumerable WebhookManagementEndpoints(IEnumerable ids) + { + throw new NotImplementedException(); + } + + public string Icon { get; } = Constants.Icon; + public string Domain { get; } = Constants.Domain; + public string About { get; } = Constants.About; + public AuthMethods AuthMethods { get; } = Constants.AuthMethods; + public IEnumerable Properties { get; } = Constants.Properties; + public Guide Guide { get; } = Constants.Guide; + public new IntegrationType Type { get; } = Constants.IntegrationType; + } +} \ No newline at end of file diff --git a/src/ExternalSearch.Providers.VatLayer/Constants.cs b/src/ExternalSearch.Providers.VatLayer/Constants.cs new file mode 100644 index 0000000..007d08a --- /dev/null +++ b/src/ExternalSearch.Providers.VatLayer/Constants.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using CluedIn.Core.Data.Relational; +using CluedIn.Core.Providers; + +namespace CluedIn.ExternalSearch.Providers.VatLayer +{ + public static class Constants + { + public const string ComponentName = "VatLayer"; + public const string ProviderName = "Vat Layer"; + public static readonly Guid ProviderId = Core.Constants.ExternalSearchProviders.VatLayerId; + + public struct KeyName + { + public const string ApiToken = "apiToken"; + + } + + public static string About { get; set; } = "VatLayer is an enricher for validating and cleaning VAT numbers"; + public static string Icon { get; set; } = "Resources.vatlayer.png"; + public static string Domain { get; set; } = "https://vatlayer.com/"; + + public static AuthMethods AuthMethods { get; set; } = new AuthMethods + { + token = new List() + { + new Control() + { + displayName = "Api Key", + type = "input", + isRequired = true, + name = KeyName.ApiToken + } + } + }; + + public static IEnumerable Properties { get; set; } = new List() + { + // NOTE: Leaving this commented as an example - BF + //new() + //{ + // displayName = "Some Data", + // type = "input", + // isRequired = true, + // name = "someData" + //} + }; + + public static Guide Guide { get; set; } = null; + public static IntegrationType IntegrationType { get; set; } = IntegrationType.Enrichment; + } +} diff --git a/src/ExternalSearch.Providers.VatLayer/Directory.Build.props b/src/ExternalSearch.Providers.VatLayer/Directory.Build.props new file mode 100644 index 0000000..2ed4d77 --- /dev/null +++ b/src/ExternalSearch.Providers.VatLayer/Directory.Build.props @@ -0,0 +1,35 @@ + + + netcoreapp3.1 + + + + + 4 + false + CS0105;CS0108;CS0109;CS0114;CS0162;CS0168;CS0169;CS0219;CS0252;CS0414;CS0472;CS0649;CS0652;CS1717;CS1998;CS4014;xUnit1013;MSB3245;MSB3270,NU1602 + + $(NoWarn);NU5105 + prompt + + + + $([System.Text.RegularExpressions.Regex]::Match($(Version), '\d+\.\d+').Value) + $([System.Text.RegularExpressions.Regex]::Match($(Version), '\d+\.\d+.\d+').Value) + CluedIn ApS + Copyright (c) 2020 $(Company). All rights reserved. + CluedIn + $(MSBuildProjectName) + $(Product).$(AssemblyTitle) + $(AssemblyName) + + + + $(RootNamespace) + $(Company) + http://cluedin.com + + + \ No newline at end of file diff --git a/src/ExternalSearch.Providers.VatLayer.csproj b/src/ExternalSearch.Providers.VatLayer/ExternalSearch.Providers.VatLayer.csproj similarity index 99% rename from src/ExternalSearch.Providers.VatLayer.csproj rename to src/ExternalSearch.Providers.VatLayer/ExternalSearch.Providers.VatLayer.csproj index a6f99c6..8ec2992 100644 --- a/src/ExternalSearch.Providers.VatLayer.csproj +++ b/src/ExternalSearch.Providers.VatLayer/ExternalSearch.Providers.VatLayer.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Models/VatLayerResponse.cs b/src/ExternalSearch.Providers.VatLayer/Models/VatLayerResponse.cs similarity index 100% rename from src/Models/VatLayerResponse.cs rename to src/ExternalSearch.Providers.VatLayer/Models/VatLayerResponse.cs diff --git a/src/Properties/AssemblyInfo.cs b/src/ExternalSearch.Providers.VatLayer/Properties/AssemblyInfo.cs similarity index 100% rename from src/Properties/AssemblyInfo.cs rename to src/ExternalSearch.Providers.VatLayer/Properties/AssemblyInfo.cs diff --git a/src/Resources/cluedin.png b/src/ExternalSearch.Providers.VatLayer/Resources/cluedin.png similarity index 100% rename from src/Resources/cluedin.png rename to src/ExternalSearch.Providers.VatLayer/Resources/cluedin.png diff --git a/src/Resources/vatlayer.png b/src/ExternalSearch.Providers.VatLayer/Resources/vatlayer.png similarity index 100% rename from src/Resources/vatlayer.png rename to src/ExternalSearch.Providers.VatLayer/Resources/vatlayer.png diff --git a/src/Utility/VatNumberCleaner.cs b/src/ExternalSearch.Providers.VatLayer/Utility/VatNumberCleaner.cs similarity index 100% rename from src/Utility/VatNumberCleaner.cs rename to src/ExternalSearch.Providers.VatLayer/Utility/VatNumberCleaner.cs diff --git a/src/ExternalSearch.Providers.VatLayer/VatLayerExternalSearchJobData.cs b/src/ExternalSearch.Providers.VatLayer/VatLayerExternalSearchJobData.cs new file mode 100644 index 0000000..da5922e --- /dev/null +++ b/src/ExternalSearch.Providers.VatLayer/VatLayerExternalSearchJobData.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using CluedIn.Core.Crawling; + +namespace CluedIn.ExternalSearch.Providers.VatLayer +{ + public class VatLayerExternalSearchJobData : CrawlJobData + { + public VatLayerExternalSearchJobData(IDictionary configuration) + { + ApiToken = GetValue(configuration, Constants.KeyName.ApiToken); + } + + public IDictionary ToDictionary() + { + return new Dictionary { + { Constants.KeyName.ApiToken, ApiToken } + }; + } + + public string ApiToken { get; set; } + } +} diff --git a/src/VatLayerExternalSearchProvider.cs b/src/ExternalSearch.Providers.VatLayer/VatLayerExternalSearchProvider.cs similarity index 75% rename from src/VatLayerExternalSearchProvider.cs rename to src/ExternalSearch.Providers.VatLayer/VatLayerExternalSearchProvider.cs index dc62cd3..01bcf12 100644 --- a/src/VatLayerExternalSearchProvider.cs +++ b/src/ExternalSearch.Providers.VatLayer/VatLayerExternalSearchProvider.cs @@ -21,16 +21,18 @@ namespace CluedIn.ExternalSearch.Providers.VatLayer { + /// The VatLayer graph external search provider. /// - public class VatLayerExternalSearchProvider : ExternalSearchProviderBase, IExtendedEnricherMetadata + public class VatLayerExternalSearchProvider : ExternalSearchProviderBase, IExtendedEnricherMetadata, IConfigurableExternalSearchProvider { + private static readonly EntityType[] AcceptedEntityTypes = { EntityType.Organization }; /********************************************************************************************************** * CONSTRUCTORS **********************************************************************************************************/ public VatLayerExternalSearchProvider() - : base(Constants.ExternalSearchProviders.VatLayerId, EntityType.Organization) + : base(Constants.ProviderId, AcceptedEntityTypes) { var nameBasedTokenProvider = new NameBasedTokenProvider("VatLayer"); @@ -68,6 +70,16 @@ private VatLayerExternalSearchProvider(bool tokenProviderIsRequired) /// The request. /// The search queries. public override IEnumerable BuildQueries(ExecutionContext context, IExternalSearchRequest request) + { + var apiToken = TokenProvider?.ApiToken; + + foreach (var externalSearchQuery in InternalBuildQueries(context, request, apiToken)) + { + yield return externalSearchQuery; + } + } + + private IEnumerable InternalBuildQueries(ExecutionContext context, IExternalSearchRequest request, string apiToken) { if (context == null) { @@ -81,7 +93,7 @@ public override IEnumerable BuildQueries(ExecutionContext using (context.Log.BeginScope($"{GetType().Name} BuildQueries: request {request}")) { - if (string.IsNullOrEmpty(TokenProvider?.ApiToken)) + if (string.IsNullOrEmpty(apiToken)) { context.Log.LogError("ApiToken for VatLayer must be provided."); yield break; @@ -89,12 +101,12 @@ public override IEnumerable BuildQueries(ExecutionContext if (!Accepts(request.EntityMetaData.EntityType)) { - context.Log.LogTrace("Unacceptable entity type from '{EntityName}', entity code '{EntityCode}'",request.EntityMetaData.DisplayName, request.EntityMetaData.EntityType.Code); + context.Log.LogTrace("Unacceptable entity type from '{EntityName}', entity code '{EntityCode}'", request.EntityMetaData.DisplayName, request.EntityMetaData.EntityType.Code); yield break; } - context.Log.LogTrace("Starting to build queries for {EntityName}",request.EntityMetaData.DisplayName); + context.Log.LogTrace("Starting to build queries for {EntityName}", request.EntityMetaData.DisplayName); var existingResults = request.GetQueryResults(this).ToList(); @@ -104,7 +116,7 @@ public override IEnumerable BuildQueries(ExecutionContext var vatNumber = request.QueryParameters.GetValue(Core.Data.Vocabularies.Vocabularies.CluedInOrganization.VatNumber, new HashSet()); if (!vatNumber.Any()) { - context.Log.LogTrace("No query parameter for '{VatNumber}' in request, skipping build queries",Core.Data.Vocabularies.Vocabularies.CluedInOrganization.VatNumber); + context.Log.LogTrace("No query parameter for '{VatNumber}' in request, skipping build queries", Core.Data.Vocabularies.Vocabularies.CluedInOrganization.VatNumber); } else { @@ -124,16 +136,16 @@ public override IEnumerable BuildQueries(ExecutionContext if (value != sanitizedValue) { - context.Log.LogTrace("Sanitized VAT number. Original '{OriginalValue}', Updated '{SanitizedValue}'",value,sanitizedValue); + context.Log.LogTrace("Sanitized VAT number. Original '{OriginalValue}', Updated '{SanitizedValue}'", value, sanitizedValue); } - context.Log.LogInformation("External search query produced, ExternalSearchQueryParameter: '{Identifier}' EntityType: '{EntityCode}' Value: '{SanitizedValue}'",ExternalSearchQueryParameter.Identifier,entityType.Code,sanitizedValue); + context.Log.LogInformation("External search query produced, ExternalSearchQueryParameter: '{Identifier}' EntityType: '{EntityCode}' Value: '{SanitizedValue}'", ExternalSearchQueryParameter.Identifier, entityType.Code, sanitizedValue); yield return new ExternalSearchQuery(this, entityType, ExternalSearchQueryParameter.Identifier, sanitizedValue); } } - context.Log.LogTrace("Finished building queries for '{Name}'",request.EntityMetaData.Name); + context.Log.LogTrace("Finished building queries for '{Name}'", request.EntityMetaData.Name); } } } @@ -144,6 +156,21 @@ public override IEnumerable BuildQueries(ExecutionContext /// The results. public override IEnumerable ExecuteSearch(ExecutionContext context, IExternalSearchQuery query) { + var apiToken = TokenProvider?.ApiToken; + + foreach (var externalSearchQueryResult in InternalExecuteSearch(context, query, apiToken)) + { + yield return externalSearchQueryResult; + } + } + + private IEnumerable InternalExecuteSearch(ExecutionContext context, IExternalSearchQuery query, string apiToken) + { + if (string.IsNullOrEmpty(apiToken)) + { + throw new InvalidOperationException("ApiToken for VatLayer must be provided."); + } + if (context == null) { throw new ArgumentNullException(nameof(context)); @@ -156,18 +183,13 @@ public override IEnumerable ExecuteSearch(ExecutionC using (context.Log.BeginScope("{0} {1}: query {2}", GetType().Name, "ExecuteSearch", query)) { - if (string.IsNullOrEmpty(TokenProvider?.ApiToken)) - { - throw new InvalidOperationException("ApiToken for VatLayer must be provided."); - } - - context.Log.LogTrace("Starting external search for Id: '{Id}' QueryKey: '{QueryKey}'",query.Id,query.QueryKey); + context.Log.LogTrace("Starting external search for Id: '{Id}' QueryKey: '{QueryKey}'", query.Id, query.QueryKey); var vat = query.QueryParameters[ExternalSearchQueryParameter.Identifier].FirstOrDefault(); if (string.IsNullOrEmpty(vat)) { - context.Log.LogTrace("No parameter for '{Identifier}' in query, skipping execute search",ExternalSearchQueryParameter.Identifier); + context.Log.LogTrace("No parameter for '{Identifier}' in query, skipping execute search", ExternalSearchQueryParameter.Identifier); } else { @@ -175,7 +197,7 @@ public override IEnumerable ExecuteSearch(ExecutionC vat = WebUtility.UrlEncode(vat); var client = new RestClient("http://www.apilayer.net/api"); - var request = new RestRequest($"validate?access_key={TokenProvider.ApiToken}&vat_number={vat}&format=1", + var request = new RestRequest($"validate?access_key={apiToken}&vat_number={vat}&format=1", Method.GET); var response = client.ExecuteAsync(request).Result; @@ -236,7 +258,7 @@ public override IEnumerable ExecuteSearch(ExecutionC throw new ApplicationException(diagnostic); } - context.Log.LogTrace("Finished external search for Id: '{Id}' QueryKey: '{QueryKey}'",query.Id,query.QueryKey); + context.Log.LogTrace("Finished external search for Id: '{Id}' QueryKey: '{QueryKey}'", query.Id, query.QueryKey); } } } @@ -282,9 +304,9 @@ public override IEnumerable BuildClues(ExecutionContext context, clue.Data.EntityData.Codes.Add(new EntityCode(EntityType.Organization, CodeOrigin.CluedIn.CreateSpecific("vatlayer"), dirtyClue)); PopulateMetadata(clue.Data.EntityData, resultItem); - context.Log.LogInformation("Clue produced, Id: '{Id}' OriginEntityCode: '{OriginEntityCode}' RawText: '{RawText}'",clue.Id,clue.OriginEntityCode,clue.RawText); + context.Log.LogInformation("Clue produced, Id: '{Id}' OriginEntityCode: '{OriginEntityCode}' RawText: '{RawText}'", clue.Id, clue.OriginEntityCode, clue.RawText); - return new[] {clue}; + return new[] { clue }; } } @@ -314,9 +336,9 @@ public override IEntityMetadata GetPrimaryEntityMetadata(ExecutionContext contex using (context.Log.BeginScope("{0} {1}: request {2}, result {3}", GetType().Name, "GetPrimaryEntityMetadata", request, result)) { - var metadata = CreateMetadata(result.As()); + var metadata = CreateMetadata(result.As()); - context.Log.LogInformation("Primary entity meta data created, Name: '{Name}' OriginEntityCode: '{OriginEntityCode}'",metadata.Name,metadata.OriginEntityCode.Origin.Code); + context.Log.LogInformation("Primary entity meta data created, Name: '{Name}' OriginEntityCode: '{OriginEntityCode}'", metadata.Name, metadata.OriginEntityCode.Origin.Code); return metadata; } @@ -370,28 +392,71 @@ private static void PopulateMetadata(IEntityMetadata metadata, IExternalSearchQu { var code = GetOriginEntityCode(resultItem); - metadata.EntityType = EntityType.Organization; - metadata.Name = resultItem.Data.CompanyName; - metadata.OriginEntityCode = code; + metadata.EntityType = EntityType.Organization; + metadata.Name = resultItem.Data.CompanyName; + metadata.OriginEntityCode = code; metadata.Codes.Add(code); - metadata.Properties[VatLayerVocabulary.Organization.Name] = resultItem.Data.CompanyName; + metadata.Properties[VatLayerVocabulary.Organization.Name] = resultItem.Data.CompanyName; - metadata.Properties[VatLayerVocabulary.Organization.CountryCode] = resultItem.Data.CountryCode; + metadata.Properties[VatLayerVocabulary.Organization.CountryCode] = resultItem.Data.CountryCode; - metadata.Properties[VatLayerVocabulary.Organization.CvrNumber] = resultItem.Data.VatNumber; + metadata.Properties[VatLayerVocabulary.Organization.CvrNumber] = resultItem.Data.VatNumber; - metadata.Properties[VatLayerVocabulary.Organization.FullVAT] = resultItem.Data.Query; + metadata.Properties[VatLayerVocabulary.Organization.FullVAT] = resultItem.Data.Query; - metadata.Properties[VatLayerVocabulary.Organization.Address] = resultItem.Data.CompanyAddress; + metadata.Properties[VatLayerVocabulary.Organization.Address] = resultItem.Data.CompanyAddress; } - public string Icon { get; } = "Resources.vatlayer.png"; - public string Domain { get; } = "https://vatlayer.com/"; - public string About { get; } = "VatLayer is an enricher for validating and cleaning VAT numbers"; - public AuthMethods AuthMethods { get; } = null; - public IEnumerable Properties { get; } = null; - public Guide Guide { get; } = null; - public IntegrationType Type { get; } = IntegrationType.Cloud; + public IEnumerable Accepts(IDictionary config, IProvider provider) + { + return AcceptedEntityTypes; + } + + public IEnumerable BuildQueries(ExecutionContext context, IExternalSearchRequest request, IDictionary config, IProvider provider) + { + var jobData = new VatLayerExternalSearchJobData(config); + + foreach (var externalSearchQuery in InternalBuildQueries(context, request, jobData.ApiToken)) + { + yield return externalSearchQuery; + } + } + + public IEnumerable ExecuteSearch(ExecutionContext context, IExternalSearchQuery query, IDictionary config, IProvider provider) + { + var jobData = new VatLayerExternalSearchJobData(config); + + foreach (var externalSearchQueryResult in InternalExecuteSearch(context, query, jobData.ApiToken)) + { + yield return externalSearchQueryResult; + } + } + + public IEnumerable BuildClues(ExecutionContext context, IExternalSearchQuery query, IExternalSearchQueryResult result, IExternalSearchRequest request, IDictionary config, IProvider provider) + { + return BuildClues(context, query, result, request); + } + + public IEntityMetadata GetPrimaryEntityMetadata(ExecutionContext context, IExternalSearchQueryResult result, IExternalSearchRequest request, IDictionary config, IProvider provider) + { + return GetPrimaryEntityMetadata(context, result, request); + } + + public IPreviewImage GetPrimaryEntityPreviewImage(ExecutionContext context, IExternalSearchQueryResult result, IExternalSearchRequest request, IDictionary config, IProvider provider) + { + return GetPrimaryEntityPreviewImage(context, result, request); + } + + public string Icon { get; } = Constants.Icon; + public string Domain { get; } = Constants.Domain; + public string About { get; } = Constants.About; + + public AuthMethods AuthMethods { get; } = Constants.AuthMethods; + public IEnumerable Properties { get; } = Constants.Properties; + public Guide Guide { get; } = Constants.Guide; + public IntegrationType Type { get; } = Constants.IntegrationType; + + } } diff --git a/src/Vocabularies/VatLayerOrganizationVocabulary.cs b/src/ExternalSearch.Providers.VatLayer/Vocabularies/VatLayerOrganizationVocabulary.cs similarity index 100% rename from src/Vocabularies/VatLayerOrganizationVocabulary.cs rename to src/ExternalSearch.Providers.VatLayer/Vocabularies/VatLayerOrganizationVocabulary.cs diff --git a/src/Vocabularies/VatLayerVocabulary.cs b/src/ExternalSearch.Providers.VatLayer/Vocabularies/VatLayerVocabulary.cs similarity index 100% rename from src/Vocabularies/VatLayerVocabulary.cs rename to src/ExternalSearch.Providers.VatLayer/Vocabularies/VatLayerVocabulary.cs diff --git a/test/integration/ExternalSearch.VatLayer.Integration.Tests/ExternalSearch.VatLayer.Integration.Tests.csproj b/test/integration/ExternalSearch.VatLayer.Integration.Tests/ExternalSearch.VatLayer.Integration.Tests.csproj index a0c9b8c..f0faed2 100644 --- a/test/integration/ExternalSearch.VatLayer.Integration.Tests/ExternalSearch.VatLayer.Integration.Tests.csproj +++ b/test/integration/ExternalSearch.VatLayer.Integration.Tests/ExternalSearch.VatLayer.Integration.Tests.csproj @@ -3,6 +3,6 @@ - + \ No newline at end of file diff --git a/test/unit/ExternalSearch.VatLayer.Unit.Tests/ExternalSearch.VatLayer.Unit.Tests.csproj b/test/unit/ExternalSearch.VatLayer.Unit.Tests/ExternalSearch.VatLayer.Unit.Tests.csproj index dbb460c..3384491 100644 --- a/test/unit/ExternalSearch.VatLayer.Unit.Tests/ExternalSearch.VatLayer.Unit.Tests.csproj +++ b/test/unit/ExternalSearch.VatLayer.Unit.Tests/ExternalSearch.VatLayer.Unit.Tests.csproj @@ -1,7 +1,8 @@  - - + + + + -