Skip to content
This repository has been archived by the owner on May 12, 2023. It is now read-only.

Add Product Model and Family Variant for Akeneo's latest version 2.3 #23

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions src/Akeneo/Akeneo.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard1.5;net451</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<PackageId>Akeneo.NET</PackageId>
<VersionPrefix>0.1.14</VersionPrefix>
<Authors>pardahlman</Authors>
Expand All @@ -13,19 +13,26 @@
<RepositoryUrl>https://github.com/pardahlman/akeneo-csharp</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>akeneo, pim</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.5</Version>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.5' ">
<DefineConstants>NETSTANDARD1_5, LIBLOG_PORTABLE</DefineConstants>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>NETSTANDARD2_0, LIBLOG_PORTABLE</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<Compile Remove="Logging\**" />
<EmbeddedResource Remove="Logging\**" />
<None Remove="Logging\**" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
<PackageReference Include="Microsoft.Net.Http" Version="2.2.29" />
<Reference Include="Microsoft.CSharp" />
<ItemGroup>
<PackageReference Include="LibLog" Version="5.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>

</Project>
68 changes: 63 additions & 5 deletions src/Akeneo/AkeneoClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class AkeneoClient : AkenioClientBase, IAkeneoClient
private readonly SearchQueryBuilder _searchBuilder;
private readonly ILog _logger = LogProvider.For<AkeneoClient>();

public AkeneoClient(AkeneoOptions options)
public AkeneoClient(AkeneoOptions options)
: this(options.ApiEndpoint, new AuthenticationClient(options.ApiEndpoint, options.ClientId, options.ClientSecret, options.UserName, options.Password)) { }

public AkeneoClient(Uri apiEndPoint, IAuthenticationClient authClient) : base(apiEndPoint, authClient)
Expand All @@ -46,7 +46,14 @@ public AkeneoClient(Uri apiEndPoint, IAuthenticationClient authClient) : base(ap
: default(TModel);
}

public async Task<TModel> GetAsync<TModel>(string parentCode, string code, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
public async Task<string> GetByUrl(string url, CancellationToken ct = default(CancellationToken))
{
_logger.Debug($"Getting resource from URL '{url}'.");
HttpResponseMessage response = await GetAsync(url, ct);
return await response.Content.ReadAsStringAsync();
}

public async Task<TModel> GetAsync<TModel>(string parentCode, string code, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var endpoint = _endpointResolver.ForResource<TModel>(parentCode, code);
_logger.Debug($"Getting resource '{typeof(TModel).Name}' from URL '{endpoint}'.");
Expand All @@ -62,7 +69,13 @@ public AkeneoClient(Uri apiEndPoint, IAuthenticationClient authClient) : base(ap
return FilterAsync<TModel>(queryString, ct);
}

public async Task<PaginationResult<TModel>> FilterAsync<TModel>(string queryString, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
public Task<List<TModel>> SearchAndGetAllAsync<TModel>(IEnumerable<Criteria> criterias, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var queryString = _searchBuilder.GetQueryStringParam(criterias);
return FilterAndGetAllAsync<TModel>(queryString, null, ct);
}

public async Task<PaginationResult<TModel>> FilterAsync<TModel>(string queryString, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var endpoint = _endpointResolver.ForResourceType<TModel>();
_logger.Debug($"Filtering resource '{typeof(TModel).Name}' from URL '{endpoint}' with query '{queryString}'.");
Expand All @@ -71,13 +84,36 @@ public AkeneoClient(Uri apiEndPoint, IAuthenticationClient authClient) : base(ap
result.Code = response.StatusCode;
return result;
}
public async Task<List<TModel>> FilterAndGetAllAsync<TModel>(string queryString, string cursor = null, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var endpoint = _endpointResolver.WithSearchAfter<TModel>(100, cursor);
_logger.Debug($"Filtering resource '{typeof(TModel).Name}' from URL '{endpoint}' with query '{queryString}'.");
var response = await GetAsync($"{endpoint}{queryString}", ct);

if (!response.IsSuccessStatusCode) throw new HttpRequestException($"Error while executing GET reques: {endpoint}{queryString}");

PaginationResult<TModel> paginationResult = await response.Content.ReadAsJsonAsync<PaginationResult<TModel>>();
paginationResult.Code = response.StatusCode;

List<TModel> items = paginationResult.GetItems();

public Task<PaginationResult<TModel>> GetManyAsync<TModel>(int page = 1, int limit = 10, bool withCount = false, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
var nextCursor = paginationResult.Links.GetCursor();

if (nextCursor != null)
{
var nextItems = await FilterAndGetAllAsync<TModel>(queryString, nextCursor, ct);
items.AddRange(nextItems);
}

return items;
}

public Task<PaginationResult<TModel>> GetManyAsync<TModel>(int page = 1, int limit = 10, bool withCount = false, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
return GetManyAsync<TModel>(null, page, limit, withCount, ct);
}

public async Task<PaginationResult<TModel>> GetManyAsync<TModel>(string parentCode, int page = 1, int limit = 10, bool withCount = false, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
public async Task<PaginationResult<TModel>> GetManyAsync<TModel>(string parentCode, int page = 1, int limit = 10, bool withCount = false, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var endpoint = _endpointResolver.ForPagination<TModel>(parentCode, page, limit, withCount);
_logger.Debug($"Getting multiple resource '{typeof(TModel).Name}' from URL '{endpoint}'.");
Expand All @@ -87,6 +123,28 @@ public AkeneoClient(Uri apiEndPoint, IAuthenticationClient authClient) : base(ap
: PaginationResult<TModel>.Empty;
}

public async Task<List<TModel>> GetAllAsync<TModel>(string cursor = null, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var endpoint = _endpointResolver.WithSearchAfter<TModel>(100, cursor);
_logger.Debug($"Getting multiple resource '{typeof(TModel).Name}' from URL '{endpoint}'.");
var response = await GetAsync(endpoint, ct);

if (!response.IsSuccessStatusCode) return new List<TModel>();

PaginationResult<TModel> paginationResult = await response.Content.ReadAsJsonAsync<PaginationResult<TModel>>();
var items = paginationResult.GetItems();

var nextCursor = paginationResult.Links.GetCursor();

if (nextCursor != null)
{
var nextItems = await GetAllAsync<TModel>(nextCursor, ct);
items.AddRange(nextItems);
}

return items;
}

public async Task<AkeneoResponse> CreateAsync<TModel>(TModel model, CancellationToken ct = default(CancellationToken)) where TModel : ModelBase
{
var option = model as AttributeOption;
Expand Down
15 changes: 14 additions & 1 deletion src/Akeneo/Client/PaginationResult.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Web;
using Newtonsoft.Json;

namespace Akeneo.Client
Expand Down Expand Up @@ -39,11 +41,22 @@ public static List<TItem> GetItems<TItem>(this PaginationResult<TItem> result)
public static class PaginationDictionaryExtensions
{
private static readonly string Next = "next";
private static readonly string SearchAfter = "search_after";

public static PaginationLink GetNext(this IDictionary<string, PaginationLink> links)
{
return links.ContainsKey(Next) ? links[Next] : null;
}

public static string GetCursor(this IDictionary<string, PaginationLink> links)
{
if (!links.TryGetValue(Next, out var link)) return null;

Uri myUri = new Uri(link.Href);
string cursor = HttpUtility.ParseQueryString(myUri.Query).Get(SearchAfter);
cursor = WebUtility.UrlEncode(cursor);
return cursor;
}
}


Expand Down
18 changes: 18 additions & 0 deletions src/Akeneo/Common/EndpointResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class EndpointResolver
private static readonly Type Product = typeof(Product);
private static readonly Type MediaFile = typeof(MediaFile);
private static readonly Type Locale = typeof(Locale);
private static readonly Type ProductModel = typeof(ProductModel);
private static readonly Type FamilyVariant = typeof(FamilyVariant);

private readonly ConcurrentDictionary<Type, string> _typeToEndpointCache;

Expand Down Expand Up @@ -116,6 +118,14 @@ protected virtual string GetResourceEndpoint(Type modelType)
{
return Endpoints.Locale;
}
if (ProductModel.GetTypeInfo().IsAssignableFrom(type))
{
return Endpoints.ProductModel;
}
if (FamilyVariant.GetTypeInfo().IsAssignableFrom(type))
{
return Endpoints.FamilyVariant;
}
throw new NotSupportedException($"Unable to find API endpoint for type {modelType.FullName}");
});
}
Expand All @@ -131,5 +141,13 @@ public string ForPagination<TModel>(string parentCode, int page = 1, int limit =
var baseUrl = ForResourceType<TModel>(parentCode);
return $"{baseUrl}?page={page}&limit={limit}&with_count={withCount.ToString().ToLower()}";
}

public string WithSearchAfter<TModel>(int limit = 100, string searchAfter = null) where TModel : ModelBase
{
var baseUrl = ForResourceType<TModel>();
return searchAfter == null
? $"{baseUrl}?pagination_type=search_after&limit={limit}"
: $"{baseUrl}?pagination_type=search_after&limit={limit}&search_after={searchAfter}";
}
}
}
4 changes: 3 additions & 1 deletion src/Akeneo/Common/Endpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class Endpoints
public const string Families = "api/rest/v1/families";
public const string MediaFiles = "api/rest/v1/media-files";
public const string Locale = "api/rest/v1/locales";
public const string ProductModel = "api/rest/v1/product-models";
public const string FamilyVariant = "/api/rest/v1/families/{1}/variants";
}
}
}
Loading