Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/del 2757 languages in sdk #256

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,16 @@ public static Task<IDeliveryTaxonomyListingResponse> GetTaxonomiesAsync(this IDe
{
return client.GetTaxonomiesAsync(parameters);
}

/// <summary>
/// Returns languages.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we be a bit more specific? Something like "returns all active languages assigned to a given project and matching the optional filtering parameters."...

/// </summary>
/// <param name="client">An instance of the <see cref="IDeliveryClient"/></param>
/// <param name="parameters">An array that contains zero or more query parameters, for example, for paging.</param>
/// <returns>The <see cref="IDeliveryLanguageListingResponse"/> instance that represents the languages. If no query parameters are specified, all languages are returned.</returns>
public static Task<IDeliveryLanguageListingResponse> GetLanguagesAsync(this IDeliveryClient client, params IQueryParameter[] parameters)
{
return client.GetLanguagesAsync(parameters);
}
}
}
8 changes: 8 additions & 0 deletions Kentico.Kontent.Delivery.Abstractions/IDeliveryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,13 @@ public interface IDeliveryClient
/// <param name="parameters">A collection of query parameters, for example, for paging.</param>
/// <returns>The <see cref="IDeliveryTaxonomyListingResponse"/> instance that represents the taxonomy groups. If no query parameters are specified, all taxonomy groups are returned.</returns>
Task<IDeliveryTaxonomyListingResponse> GetTaxonomiesAsync(IEnumerable<IQueryParameter> parameters = null);


/// <summary>
/// Returns languages.
petrsvihlik marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="parameters">A collection of query parameters, for example, for paging.</param>
/// <returns>The <see cref="IDeliveryLanguageListingResponse"/> instance that represents the languages. If no query parameters are specified, all languages are returned.</returns>
Task<IDeliveryLanguageListingResponse> GetLanguagesAsync(IEnumerable<IQueryParameter> parameters = null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;

namespace Kentico.Kontent.Delivery.Abstractions
{
/// <summary>
/// Represents a response from Kentico Kontent Delivery API that contains a list of languages.
/// </summary>
public interface IDeliveryLanguageListingResponse : IResponse, IPageable
{
/// <summary>
/// Gets a read-only list of languages.
/// </summary>
IList<ILanguage> Languages { get; }
}
}
13 changes: 13 additions & 0 deletions Kentico.Kontent.Delivery.Abstractions/Languages/ILanguage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Kentico.Kontent.Delivery.Abstractions
{
/// <summary>
/// Represents a language.
/// </summary>
public interface ILanguage
{
/// <summary>
/// Gets the system attributes of the language.
/// </summary>
ILanguageSystemAttributes System { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Kentico.Kontent.Delivery.Abstractions
{
/// <summary>
/// Represents system attributes of a language.
/// </summary>
public interface ILanguageSystemAttributes : ISystemBaseAttributes
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,13 @@
namespace Kentico.Kontent.Delivery.Abstractions
{
/// <summary>
/// Represents system attributes of any object in Kentico Kontent.
/// Represents system attributes of ContentItem, ContentType and Taxonomy objects in Kentico Kontent.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this abstraction should know nothing about the objects that implement it. therefore even this comment seems to be irrelevant.

/// </summary>
public interface ISystemAttributes
public interface ISystemAttributes : ISystemBaseAttributes
{
/// <summary>
/// Gets the codename of the object.
/// </summary>
string Codename { get; }

/// <summary>
/// Gets the identifier of the object.
/// </summary>
string Id { get; }

/// <summary>
/// Gets the time the object was last modified.
/// </summary>
DateTime LastModified { get; }
petrsvihlik marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Gets the name of the object.
/// </summary>
string Name { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Kentico.Kontent.Delivery.Abstractions
{
/// <summary>
/// Represents system base attributes of any object in Kentico Kontent.
/// </summary>
public interface ISystemBaseAttributes
{
/// <summary>
/// Gets the codename of the object.
/// </summary>
string Codename { get; }

/// <summary>
/// Gets the identifier of the object.
/// </summary>
string Id { get; }

/// <summary>
/// Gets the name of the object.
/// </summary>
string Name { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -606,5 +606,86 @@ public async Task GetTaxonomiesAsync_InvalidatedByTaxonomiesDependency(CacheExpi
}

#endregion

#region GetLanguages

[Theory]
[InlineData(CacheTypeEnum.Memory, CacheExpirationType.Absolute)]
[InlineData(CacheTypeEnum.Memory, CacheExpirationType.Sliding)]
[InlineData(CacheTypeEnum.Distributed, CacheExpirationType.Absolute)]
[InlineData(CacheTypeEnum.Distributed, CacheExpirationType.Sliding)]
public async Task GetLanguagesAsync_ResponseIsCached(CacheTypeEnum cacheType, CacheExpirationType cacheExpirationType)
{
var url = "languages";
var languageA = CreateLanguage("language_codename", "language name");
var languages = CreateLanguagesResponse(new[] { languageA });
var updatedLanguages = CreateLanguagesResponse(new[] { languageA, CreateLanguage("second_language_codename", "Second language") });

var scenarioBuilder = new ScenarioBuilder(cacheType, cacheExpirationType);

var scenario = scenarioBuilder.WithResponse(url, languages).Build();
var firstResponse = await scenario.CachingClient.GetLanguagesAsync();

scenario = scenarioBuilder.WithResponse(url, updatedLanguages).Build();
var secondResponse = await scenario.CachingClient.GetLanguagesAsync();

firstResponse.Should().NotBeNull();
firstResponse.Should().BeEquivalentTo(secondResponse, o => o.DateTimesBsonCorrection());
scenario.GetRequestCount(url).Should().Be(1);
}

[Theory]
[InlineData(CacheTypeEnum.Memory, CacheExpirationType.Absolute)]
[InlineData(CacheTypeEnum.Memory, CacheExpirationType.Sliding)]
[InlineData(CacheTypeEnum.Distributed, CacheExpirationType.Absolute)]
[InlineData(CacheTypeEnum.Distributed, CacheExpirationType.Sliding)]
public async Task GetLanguagesAsync_InvalidatedByLanguagesKey(CacheTypeEnum cacheType, CacheExpirationType cacheExpirationType)
{
var url = "languages";
var languageA = CreateLanguage("language_codename", "language name");
var languages = CreateLanguagesResponse(new[] { languageA });
var updatedLanguages = CreateLanguagesResponse(new[] { languageA, CreateLanguage("second_language_codename", "Second language") });

var scenarioBuilder = new ScenarioBuilder(cacheType, cacheExpirationType);

var scenario = scenarioBuilder.WithResponse(url, languages).Build();
var firstResponse = await scenario.CachingClient.GetLanguagesAsync();

scenario = scenarioBuilder.WithResponse(url, updatedLanguages).Build();
scenario.InvalidateDependency(CacheHelpers.GetLanguagesKey(null));
var secondResponse = await scenario.CachingClient.GetLanguagesAsync();

firstResponse.Should().NotBeNull();
secondResponse.Should().NotBeNull();
firstResponse.Should().NotBeEquivalentTo(secondResponse);
scenario.GetRequestCount(url).Should().Be(2);
}

[Theory]
[InlineData(CacheExpirationType.Absolute)]
[InlineData(CacheExpirationType.Sliding)]
public async Task GetLanguagesAsync_InvalidatedByLanguagesDependency(CacheExpirationType cacheExpirationType)
{
var url = "languages";
var languageA = CreateLanguage("language_codename", "language name");
var languages = CreateLanguagesResponse(new[] { languageA });
var updatedLanguages = CreateLanguagesResponse(new[] { languageA, CreateLanguage("second_language_codename", "Second language") });

var scenarioBuilder = new ScenarioBuilder(cacheExpirationType: cacheExpirationType);

var scenario = scenarioBuilder.WithResponse(url, languages).Build();
var firstResponse = await scenario.CachingClient.GetLanguagesAsync();

scenario = scenarioBuilder.WithResponse(url, updatedLanguages).Build();
scenario.InvalidateDependency(CacheHelpers.GetLanguagesDependencyKey());
var secondResponse = await scenario.CachingClient.GetLanguagesAsync();

firstResponse.Should().NotBeNull();
secondResponse.Should().NotBeNull();
firstResponse.Should().NotBeEquivalentTo(secondResponse);
scenario.GetRequestCount(url).Should().Be(2);
}

#endregion
}
}
22 changes: 22 additions & 0 deletions Kentico.Kontent.Delivery.Caching.Tests/ResponseHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ public static class ResponseHelper
}
};

internal static object CreateLanguagesResponse(ICollection<object> languages) => new
{
languages,
pagination = new
{
skip = 0,
limit = 0,
count = languages.Count,
next_page = ""
}
};

internal static object CreateItem(string codename, string value = null) => new
{
elements = new Dictionary<string, object>
Expand Down Expand Up @@ -135,6 +147,16 @@ internal static (string codename, object item) CreateComponent()
}
};

internal static object CreateLanguage(string codename, string name) => new
{
system = new
{
id = Guid.NewGuid().ToString(),
codename,
name
}
};

internal static object CreateContentElement(string codename, string name) => new
{
type = "text",
Expand Down
34 changes: 34 additions & 0 deletions Kentico.Kontent.Delivery.Caching/CacheHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ public static class CacheHelpers
private const string TAXONOMY_GROUP_IDENTIFIER = "taxonomy_group";
private const string TAXONOMY_GROUP_LISTING_IDENTIFIER = "taxonomy_group_listing";

private const string LANGUAGE_LISTING_IDENTIFIER = "language_listing";

private const string CONTENT_TYPE_ELEMENT_IDENTIFIER = "content_type_element";

private const string DEPENDENCY_ITEM = "dependency_item";
private const string DEPENDENCY_ITEM_LISTING = "dependency_item_listing";
private const string DEPENDENCY_TYPE_LISTING = "dependency_type_listing";
private const string DEPENDENCY_TAXONOMY_GROUP = "dependency_taxonomy_group";
private const string DEPENDENCY_TAXONOMY_GROUP_LISTING = "dependency_taxonomy_group_listing";
private const string DEPENDENCY_LANGUAGE_LISTING = "dependency_language_listing";

#endregion

Expand Down Expand Up @@ -100,6 +103,16 @@ public static string GetTaxonomiesKey(IEnumerable<IQueryParameter> parameters)
return StringHelpers.Join(new[] { TAXONOMY_GROUP_LISTING_IDENTIFIER }.Concat(parameters?.Select(x => x.GetQueryStringParameter()) ?? Enumerable.Empty<string>()));
}

/// <summary>
/// Gets Languages dependency key
/// </summary>
/// <param name="parameters">Query Parameters</param>
/// <returns>Dependency key</returns>
public static string GetLanguagesKey(IEnumerable<IQueryParameter> parameters)
{
return StringHelpers.Join(new[] { LANGUAGE_LISTING_IDENTIFIER }.Concat(parameters?.Select(x => x.GetQueryStringParameter()) ?? Enumerable.Empty<string>()));
}

/// <summary>
/// Gets a ContentElement dependency key
/// </summary>
Expand Down Expand Up @@ -161,6 +174,15 @@ public static string GetTaxonomiesDependencyKey()
return DEPENDENCY_TAXONOMY_GROUP_LISTING;
}

/// <summary>
/// Gets Languages dependency key
/// </summary>
/// <returns>Dependency key</returns>
public static string GetLanguagesDependencyKey()
{
return DEPENDENCY_LANGUAGE_LISTING;
}

#endregion

#region Dependecies
Expand Down Expand Up @@ -282,6 +304,18 @@ public static IEnumerable<string> GetTaxonomiesDependencies(IDeliveryTaxonomyLis
: Enumerable.Empty<string>();
}

/// <summary>
/// Gets languages dependency keys from response
/// </summary>
/// <param name="response">Response</param>
/// <returns>Dependency keys</returns>
public static IEnumerable<string> GetlanguagesDependencies(IDeliveryLanguageListingResponse response)
petrsvihlik marked this conversation as resolved.
Show resolved Hide resolved
{
return response?.Languages != null
? new[] { GetLanguagesDependencyKey() }
: Enumerable.Empty<string>();
}

#endregion

private static bool IsItemResponse(IResponse response)
Expand Down
15 changes: 15 additions & 0 deletions Kentico.Kontent.Delivery.Caching/DeliveryClientCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,20 @@ public async Task<IDeliveryTaxonomyListingResponse> GetTaxonomiesAsync(IEnumerab
response => response.Taxonomies.Any(),
CacheHelpers.GetTaxonomiesDependencies);
}

/// <summary>
/// Returns languages.
/// </summary>
/// <param name="parameters">A collection of query parameters, for example, for paging.</param>
/// <returns>The <see cref="IDeliveryLanguageListingResponse"/> instance that represents the languages. If no query parameters are specified, all languages are returned.</returns>
public async Task<IDeliveryLanguageListingResponse> GetLanguagesAsync(IEnumerable<IQueryParameter> parameters = null)
{
var queryParameters = parameters?.ToList();
return await _deliveryCacheManager.GetOrAddAsync(
CacheHelpers.GetLanguagesKey(queryParameters),
() => _deliveryClient.GetLanguagesAsync(queryParameters),
response => response.Languages.Any(),
CacheHelpers.GetlanguagesDependencies);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ public void TaxonomiesRetrieved()
Assert.All(taxonomies, taxonomy => Assert.NotNull(taxonomy.Terms));
}

[Fact]
public void LanguagesRetrieved()
{
var observable = new DeliveryObservableProxy(GetDeliveryClient(MockLanguages)).GetLanguagesObservable(new SkipParameter(1));
var languages = observable.ToEnumerable().ToList();

Assert.NotEmpty(languages);
Assert.All(languages, language => Assert.NotNull(language.System));
}

private IDeliveryClient GetDeliveryClient(Action mockAction)
{
mockAction();
Expand Down Expand Up @@ -263,6 +273,13 @@ private void MockTaxonomies()
.Respond("application/json", File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"Fixtures{Path.DirectorySeparatorChar}taxonomies_multiple.json")));
}

private void MockLanguages()
{
_mockHttp.When($"{_baseUrl}/languages")
.WithQueryString("skip=1")
.Respond("application/json", File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"Fixtures{Path.DirectorySeparatorChar}languages.json")));
}

private static void AssertArticlePropertiesNotNull(Article item)
{
Assert.NotNull(item.System);
Expand Down