diff --git a/Kentico.Kontent.Delivery.Abstractions/DeliveryClientExtensions.cs b/Kentico.Kontent.Delivery.Abstractions/DeliveryClientExtensions.cs index fd6efbe2..c4bad953 100644 --- a/Kentico.Kontent.Delivery.Abstractions/DeliveryClientExtensions.cs +++ b/Kentico.Kontent.Delivery.Abstractions/DeliveryClientExtensions.cs @@ -65,5 +65,16 @@ public static Task GetTaxonomiesAsync(this IDe { return client.GetTaxonomiesAsync(parameters); } + + /// + /// Returns all active languages assigned to a given project and matching the optional filtering parameters. + /// + /// An instance of the + /// An array that contains zero or more query parameters, for example, for paging. + /// The instance that represents the languages. If no query parameters are specified, all languages are returned. + public static Task GetLanguagesAsync(this IDeliveryClient client, params IQueryParameter[] parameters) + { + return client.GetLanguagesAsync(parameters); + } } } diff --git a/Kentico.Kontent.Delivery.Abstractions/IDeliveryClient.cs b/Kentico.Kontent.Delivery.Abstractions/IDeliveryClient.cs index 9f84b2b6..eb406445 100644 --- a/Kentico.Kontent.Delivery.Abstractions/IDeliveryClient.cs +++ b/Kentico.Kontent.Delivery.Abstractions/IDeliveryClient.cs @@ -68,5 +68,13 @@ public interface IDeliveryClient /// A collection of query parameters, for example, for paging. /// The instance that represents the taxonomy groups. If no query parameters are specified, all taxonomy groups are returned. Task GetTaxonomiesAsync(IEnumerable parameters = null); + + + /// + /// Returns all active languages assigned to a given project and matching the optional filtering parameters. + /// + /// A collection of query parameters, for example, for paging. + /// The instance that represents the languages. If no query parameters are specified, all languages are returned. + Task GetLanguagesAsync(IEnumerable parameters = null); } } \ No newline at end of file diff --git a/Kentico.Kontent.Delivery.Abstractions/Languages/IDeliveryLanguageListingResponse.cs b/Kentico.Kontent.Delivery.Abstractions/Languages/IDeliveryLanguageListingResponse.cs new file mode 100644 index 00000000..70c857e0 --- /dev/null +++ b/Kentico.Kontent.Delivery.Abstractions/Languages/IDeliveryLanguageListingResponse.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Kentico.Kontent.Delivery.Abstractions +{ + /// + /// Represents a response from Kentico Kontent Delivery API that contains a list of languages. + /// + public interface IDeliveryLanguageListingResponse : IResponse, IPageable + { + /// + /// Gets a read-only list of languages. + /// + IList Languages { get; } + } +} diff --git a/Kentico.Kontent.Delivery.Abstractions/Languages/ILanguage.cs b/Kentico.Kontent.Delivery.Abstractions/Languages/ILanguage.cs new file mode 100644 index 00000000..fdc614fd --- /dev/null +++ b/Kentico.Kontent.Delivery.Abstractions/Languages/ILanguage.cs @@ -0,0 +1,13 @@ +namespace Kentico.Kontent.Delivery.Abstractions +{ + /// + /// Represents a language. + /// + public interface ILanguage + { + /// + /// Gets the system attributes of the language. + /// + ILanguageSystemAttributes System { get; } + } +} diff --git a/Kentico.Kontent.Delivery.Abstractions/Languages/ILanguageSystemAttributes.cs b/Kentico.Kontent.Delivery.Abstractions/Languages/ILanguageSystemAttributes.cs new file mode 100644 index 00000000..0013cb8d --- /dev/null +++ b/Kentico.Kontent.Delivery.Abstractions/Languages/ILanguageSystemAttributes.cs @@ -0,0 +1,9 @@ +namespace Kentico.Kontent.Delivery.Abstractions +{ + /// + /// Represents system attributes of a language. + /// + public interface ILanguageSystemAttributes : ISystemBaseAttributes + { + } +} diff --git a/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemAttributes.cs b/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemAttributes.cs index 1c522c79..6b548f05 100644 --- a/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemAttributes.cs +++ b/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemAttributes.cs @@ -3,28 +3,13 @@ namespace Kentico.Kontent.Delivery.Abstractions { /// - /// Represents system attributes of any object in Kentico Kontent. + /// Represents extended system attributes of any object in Kentico Kontent. /// - public interface ISystemAttributes + public interface ISystemAttributes : ISystemBaseAttributes { - /// - /// Gets the codename of the object. - /// - string Codename { get; } - - /// - /// Gets the identifier of the object. - /// - string Id { get; } - /// /// Gets the time the object was last modified. /// DateTime LastModified { get; } - - /// - /// Gets the name of the object. - /// - string Name { get; } } } diff --git a/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemBaseAttributes.cs b/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemBaseAttributes.cs new file mode 100644 index 00000000..f5565bad --- /dev/null +++ b/Kentico.Kontent.Delivery.Abstractions/SharedModels/ISystemBaseAttributes.cs @@ -0,0 +1,23 @@ +namespace Kentico.Kontent.Delivery.Abstractions +{ + /// + /// Represents system base attributes of any object in Kentico Kontent. + /// + public interface ISystemBaseAttributes + { + /// + /// Gets the codename of the object. + /// + string Codename { get; } + + /// + /// Gets the identifier of the object. + /// + string Id { get; } + + /// + /// Gets the name of the object. + /// + string Name { get; } + } +} diff --git a/Kentico.Kontent.Delivery.Caching.Tests/DeliveryClientCacheTests.cs b/Kentico.Kontent.Delivery.Caching.Tests/DeliveryClientCacheTests.cs index 59a7bae1..04bcd0fc 100644 --- a/Kentico.Kontent.Delivery.Caching.Tests/DeliveryClientCacheTests.cs +++ b/Kentico.Kontent.Delivery.Caching.Tests/DeliveryClientCacheTests.cs @@ -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 } } diff --git a/Kentico.Kontent.Delivery.Caching.Tests/ResponseHelper.cs b/Kentico.Kontent.Delivery.Caching.Tests/ResponseHelper.cs index 6160786d..0401a06d 100644 --- a/Kentico.Kontent.Delivery.Caching.Tests/ResponseHelper.cs +++ b/Kentico.Kontent.Delivery.Caching.Tests/ResponseHelper.cs @@ -55,6 +55,18 @@ public static class ResponseHelper } }; + internal static object CreateLanguagesResponse(ICollection 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 @@ -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", diff --git a/Kentico.Kontent.Delivery.Caching/CacheHelpers.cs b/Kentico.Kontent.Delivery.Caching/CacheHelpers.cs index 815f42db..fb263df3 100644 --- a/Kentico.Kontent.Delivery.Caching/CacheHelpers.cs +++ b/Kentico.Kontent.Delivery.Caching/CacheHelpers.cs @@ -24,6 +24,8 @@ 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"; @@ -31,6 +33,7 @@ public static class CacheHelpers 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 @@ -100,6 +103,16 @@ public static string GetTaxonomiesKey(IEnumerable parameters) return StringHelpers.Join(new[] { TAXONOMY_GROUP_LISTING_IDENTIFIER }.Concat(parameters?.Select(x => x.GetQueryStringParameter()) ?? Enumerable.Empty())); } + /// + /// Gets Languages dependency key + /// + /// Query Parameters + /// Dependency key + public static string GetLanguagesKey(IEnumerable parameters) + { + return StringHelpers.Join(new[] { LANGUAGE_LISTING_IDENTIFIER }.Concat(parameters?.Select(x => x.GetQueryStringParameter()) ?? Enumerable.Empty())); + } + /// /// Gets a ContentElement dependency key /// @@ -161,6 +174,15 @@ public static string GetTaxonomiesDependencyKey() return DEPENDENCY_TAXONOMY_GROUP_LISTING; } + /// + /// Gets Languages dependency key + /// + /// Dependency key + public static string GetLanguagesDependencyKey() + { + return DEPENDENCY_LANGUAGE_LISTING; + } + #endregion #region Dependecies @@ -282,6 +304,18 @@ public static IEnumerable GetTaxonomiesDependencies(IDeliveryTaxonomyLis : Enumerable.Empty(); } + /// + /// Gets languages dependency keys from response + /// + /// Response + /// Dependency keys + public static IEnumerable GetLanguagesDependencies(IDeliveryLanguageListingResponse response) + { + return response?.Languages != null + ? new[] { GetLanguagesDependencyKey() } + : Enumerable.Empty(); + } + #endregion private static bool IsItemResponse(IResponse response) diff --git a/Kentico.Kontent.Delivery.Caching/DeliveryClientCache.cs b/Kentico.Kontent.Delivery.Caching/DeliveryClientCache.cs index 8093de68..6aace8ff 100644 --- a/Kentico.Kontent.Delivery.Caching/DeliveryClientCache.cs +++ b/Kentico.Kontent.Delivery.Caching/DeliveryClientCache.cs @@ -141,5 +141,20 @@ public async Task GetTaxonomiesAsync(IEnumerab response => response.Taxonomies.Any(), CacheHelpers.GetTaxonomiesDependencies); } + + /// + /// Returns languages. + /// + /// A collection of query parameters, for example, for paging. + /// The instance that represents the languages. If no query parameters are specified, all languages are returned. + public async Task GetLanguagesAsync(IEnumerable parameters = null) + { + var queryParameters = parameters?.ToList(); + return await _deliveryCacheManager.GetOrAddAsync( + CacheHelpers.GetLanguagesKey(queryParameters), + () => _deliveryClient.GetLanguagesAsync(queryParameters), + response => response.Languages.Any(), + CacheHelpers.GetLanguagesDependencies); + } } } diff --git a/Kentico.Kontent.Delivery.Rx.Tests/DeliveryObservableProxyTests.cs b/Kentico.Kontent.Delivery.Rx.Tests/DeliveryObservableProxyTests.cs index 7e50631f..a2c41a8a 100644 --- a/Kentico.Kontent.Delivery.Rx.Tests/DeliveryObservableProxyTests.cs +++ b/Kentico.Kontent.Delivery.Rx.Tests/DeliveryObservableProxyTests.cs @@ -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(); @@ -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); diff --git a/Kentico.Kontent.Delivery.Rx.Tests/Fixtures/languages.json b/Kentico.Kontent.Delivery.Rx.Tests/Fixtures/languages.json new file mode 100644 index 00000000..ace3db0a --- /dev/null +++ b/Kentico.Kontent.Delivery.Rx.Tests/Fixtures/languages.json @@ -0,0 +1,31 @@ +{ + "languages": [ + { + "system": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "Default project language", + "codename": "default" + } + }, + { + "system": { + "id": "8fab3c4c-2ba4-47a9-8e53-df8e6154054f", + "name": "First Lanugage", + "codename": "first_language" + } + }, + { + "system": { + "id": "24d5aaa6-a0db-4e20-8c11-6eb272bbe168", + "name": "Second Language", + "codename": "second_language" + } + } + ], + "pagination": { + "skip": 0, + "limit": 0, + "count": 59, + "next_page": "" + } +} \ No newline at end of file diff --git a/Kentico.Kontent.Delivery.Rx.Tests/Kentico.Kontent.Delivery.Rx.Tests.csproj b/Kentico.Kontent.Delivery.Rx.Tests/Kentico.Kontent.Delivery.Rx.Tests.csproj index f06148a2..538387bc 100644 --- a/Kentico.Kontent.Delivery.Rx.Tests/Kentico.Kontent.Delivery.Rx.Tests.csproj +++ b/Kentico.Kontent.Delivery.Rx.Tests/Kentico.Kontent.Delivery.Rx.Tests.csproj @@ -12,6 +12,7 @@ + @@ -21,6 +22,9 @@ Always + + Always + Always diff --git a/Kentico.Kontent.Delivery.Rx/DeliveryObservableProxy.cs b/Kentico.Kontent.Delivery.Rx/DeliveryObservableProxy.cs index 11a62422..f7b8496e 100644 --- a/Kentico.Kontent.Delivery.Rx/DeliveryObservableProxy.cs +++ b/Kentico.Kontent.Delivery.Rx/DeliveryObservableProxy.cs @@ -189,6 +189,26 @@ public IObservable GetTaxonomiesObservable(IEnumerable + /// Returns an observable of languages. + /// + /// A collection of query parameters, for example, for paging. + /// The that represents the language. If no query parameters are specified, all languages are returned. + public IObservable GetLanguagesObservable(IEnumerable parameters) + { + return (DeliveryClient?.GetLanguagesAsync(parameters))?.Result?.Languages?.ToObservable(); + } + + /// + /// Returns an observable of languages. + /// + /// A collection of query parameters, for example, for paging. + /// The that represents the language. If no query parameters are specified, all languages are returned. + public IObservable GetLanguagesObservable(params IQueryParameter[] parameters) + { + return GetLanguagesObservable((IEnumerable)parameters); + } + #endregion #region "Private methods" diff --git a/Kentico.Kontent.Delivery.Tests/DeliveryClientTests.cs b/Kentico.Kontent.Delivery.Tests/DeliveryClientTests.cs index 80a12b79..9ac08a09 100644 --- a/Kentico.Kontent.Delivery.Tests/DeliveryClientTests.cs +++ b/Kentico.Kontent.Delivery.Tests/DeliveryClientTests.cs @@ -553,6 +553,22 @@ public async Task GetTaxonomiesAsync() Assert.NotEmpty(response.Taxonomies); } + [Fact] + public async Task GetLanguagesAsync() + { + _mockHttp + .When($"{_baseUrl}/languages") + .WithQueryString("skip=1") + .Respond("application/json", await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, $"Fixtures{Path.DirectorySeparatorChar}DeliveryClient{Path.DirectorySeparatorChar}languages.json"))); + + var client = InitializeDeliveryClientWithACustomTypeProvider(_mockHttp); + + var response = await client.GetLanguagesAsync(new SkipParameter(1)); + + Assert.NotNull(response.ApiResponse.RequestUrl); + Assert.NotEmpty(response.Languages); + } + [Fact] public async Task QueryParameters() { @@ -1387,6 +1403,48 @@ public async Task GetTaxonomiesAsync_ApiDoesNotReturnStaleContent_ResponseDoesNo Assert.True(response.Taxonomies.Any()); } + [Fact] + public async Task GetLanguagesAsync_ApiReturnsStaleContent_ResponseIndicatesStaleContent() + { + var headers = new[] + { + new KeyValuePair("X-Stale-Content", "1") + }; + + _mockHttp + .When($"{_baseUrl}/languages") + .Respond(headers, "application/json", await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, + $"Fixtures{Path.DirectorySeparatorChar}DeliveryClient{Path.DirectorySeparatorChar}languages.json"))); + + var client = InitializeDeliveryClientWithCustomModelProvider(_mockHttp); + + var response = await client.GetLanguagesAsync(); + + Assert.True(response.ApiResponse.HasStaleContent); + Assert.True(response.Languages.Any()); + } + + [Fact] + public async Task GetLanguagesAsync_ApiDoesNotReturnStaleContent_ResponseDoesNotIndicateStaleContent() + { + var headers = new[] + { + new KeyValuePair("X-Stale-Content", "0") + }; + + _mockHttp + .When($"{_baseUrl}/languages") + .Respond(headers, "application/json", await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, + $"Fixtures{Path.DirectorySeparatorChar}DeliveryClient{Path.DirectorySeparatorChar}languages.json"))); + + var client = InitializeDeliveryClientWithCustomModelProvider(_mockHttp); + + var response = await client.GetLanguagesAsync(); + + Assert.False(response.ApiResponse.HasStaleContent); + Assert.True(response.Languages.Any()); + } + [Fact] public async Task GetElementAsync_ApiReturnsStaleContent_ResponseIndicatesStaleContent() { diff --git a/Kentico.Kontent.Delivery.Tests/Fixtures/DeliveryClient/languages.json b/Kentico.Kontent.Delivery.Tests/Fixtures/DeliveryClient/languages.json new file mode 100644 index 00000000..ace3db0a --- /dev/null +++ b/Kentico.Kontent.Delivery.Tests/Fixtures/DeliveryClient/languages.json @@ -0,0 +1,31 @@ +{ + "languages": [ + { + "system": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "Default project language", + "codename": "default" + } + }, + { + "system": { + "id": "8fab3c4c-2ba4-47a9-8e53-df8e6154054f", + "name": "First Lanugage", + "codename": "first_language" + } + }, + { + "system": { + "id": "24d5aaa6-a0db-4e20-8c11-6eb272bbe168", + "name": "Second Language", + "codename": "second_language" + } + } + ], + "pagination": { + "skip": 0, + "limit": 0, + "count": 59, + "next_page": "" + } +} \ No newline at end of file diff --git a/Kentico.Kontent.Delivery.Tests/Kentico.Kontent.Delivery.Tests.csproj b/Kentico.Kontent.Delivery.Tests/Kentico.Kontent.Delivery.Tests.csproj index aea47e9e..cc1bcb42 100644 --- a/Kentico.Kontent.Delivery.Tests/Kentico.Kontent.Delivery.Tests.csproj +++ b/Kentico.Kontent.Delivery.Tests/Kentico.Kontent.Delivery.Tests.csproj @@ -63,6 +63,9 @@ + + Always + Always diff --git a/Kentico.Kontent.Delivery/DeliveryClient.cs b/Kentico.Kontent.Delivery/DeliveryClient.cs index 7a72c7f6..5f1b3aee 100644 --- a/Kentico.Kontent.Delivery/DeliveryClient.cs +++ b/Kentico.Kontent.Delivery/DeliveryClient.cs @@ -9,6 +9,7 @@ using Kentico.Kontent.Delivery.ContentItems; using Kentico.Kontent.Delivery.ContentTypes; using Kentico.Kontent.Delivery.Extensions; +using Kentico.Kontent.Delivery.Languages; using Kentico.Kontent.Delivery.SharedModels; using Kentico.Kontent.Delivery.TaxonomyGroups; using Kentico.Kontent.Delivery.Urls; @@ -238,6 +239,21 @@ public async Task GetTaxonomiesAsync(IEnumerab return new DeliveryTaxonomyListingResponse(response, taxonomies.ToList(), pagination); } + /// + /// Returns all active languages assigned to a given project and matching the optional filtering parameters. + /// + /// A collection of query parameters, for example, for paging. + /// The instance that represents the languages. If no query parameters are specified, all languages are returned. + public async Task GetLanguagesAsync(IEnumerable parameters = null) + { + var endpointUrl = UrlBuilder.GetLanguagesUrl(parameters); + var response = await GetDeliveryResponseAsync(endpointUrl); + var content = await response.GetJsonContentAsync(); + var pagination = content["pagination"].ToObject(Serializer); + var languages = content["languages"].ToObject>(Serializer); + return new DeliveryLanguageListingResponse(response, languages.ToList(), pagination); + } + private async Task GetDeliveryResponseAsync(string endpointUrl, string continuationToken = null) { if (DeliveryOptions.CurrentValue.UsePreviewApi && DeliveryOptions.CurrentValue.UseSecureAccess) diff --git a/Kentico.Kontent.Delivery/Languages/DeliveryLanguageListingResponse.cs b/Kentico.Kontent.Delivery/Languages/DeliveryLanguageListingResponse.cs new file mode 100644 index 00000000..5e7d6086 --- /dev/null +++ b/Kentico.Kontent.Delivery/Languages/DeliveryLanguageListingResponse.cs @@ -0,0 +1,36 @@ +using Kentico.Kontent.Delivery.Abstractions; +using Kentico.Kontent.Delivery.SharedModels; +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Kentico.Kontent.Delivery.Languages +{ + /// + internal sealed class DeliveryLanguageListingResponse : AbstractResponse, IDeliveryLanguageListingResponse + { + /// + public IList Languages + { + get; + } + + /// + public IPagination Pagination + { + get; + } + + /// + /// Initializes a new instance of the class. + /// + /// The response from Kentico Kontent Delivery API that contains languages. + /// A collection of languages. + /// Response paging information. + [JsonConstructor] + internal DeliveryLanguageListingResponse(ApiResponse response, IList languages, IPagination pagination) : base(response) + { + Languages = languages; + Pagination = pagination; + } + } +} diff --git a/Kentico.Kontent.Delivery/Languages/Language.cs b/Kentico.Kontent.Delivery/Languages/Language.cs new file mode 100644 index 00000000..aa7766d3 --- /dev/null +++ b/Kentico.Kontent.Delivery/Languages/Language.cs @@ -0,0 +1,24 @@ +using Kentico.Kontent.Delivery.Abstractions; +using Newtonsoft.Json; +using System.Diagnostics; + +namespace Kentico.Kontent.Delivery.Languages +{ + /// + [DebuggerDisplay("Name = {" + nameof(System) + "." + nameof(ILanguageSystemAttributes.Name) + "}")] + internal sealed class Language : ILanguage + { + /// + [JsonProperty("system")] + public ILanguageSystemAttributes System { get; internal set; } + + /// + /// Constructor used for deserialization (e.g. for caching purposes), contains no logic. + /// + [JsonConstructor] + public Language(ILanguageSystemAttributes system) + { + System = system; + } + } +} diff --git a/Kentico.Kontent.Delivery/Languages/LanguageSystemAttributes.cs b/Kentico.Kontent.Delivery/Languages/LanguageSystemAttributes.cs new file mode 100644 index 00000000..c7c2033a --- /dev/null +++ b/Kentico.Kontent.Delivery/Languages/LanguageSystemAttributes.cs @@ -0,0 +1,31 @@ +using Kentico.Kontent.Delivery.Abstractions; +using Newtonsoft.Json; +using System.Diagnostics; + +namespace Kentico.Kontent.Delivery.Languages +{ + /// + [DebuggerDisplay("Id = {" + nameof(Id) + "}")] + public class LanguageSystemAttributes : ILanguageSystemAttributes + { + /// + [JsonProperty("codename")] + public string Codename { get; internal set; } + + /// + [JsonProperty("id")] + public string Id { get; internal set; } + + /// + [JsonProperty("name")] + public string Name { get; internal set; } + + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public LanguageSystemAttributes() + { + } + } +} diff --git a/Kentico.Kontent.Delivery/Urls/DeliveryEndpointUrlBuilder.cs b/Kentico.Kontent.Delivery/Urls/DeliveryEndpointUrlBuilder.cs index 08b56849..4e09297d 100644 --- a/Kentico.Kontent.Delivery/Urls/DeliveryEndpointUrlBuilder.cs +++ b/Kentico.Kontent.Delivery/Urls/DeliveryEndpointUrlBuilder.cs @@ -18,6 +18,7 @@ internal sealed class DeliveryEndpointUrlBuilder private const string UrlTemplateElement = "/types/{0}/elements/{1}"; private const string UrlTemplateTaxonomy = "/taxonomies/{0}"; private const string UrlTemplateTaxonomies = "/taxonomies"; + private const string UrlTemplateLanguages = "/languages"; private readonly IOptionsMonitor _deliveryOptions; @@ -67,6 +68,11 @@ public string GetTaxonomiesUrl(IEnumerable parameters) return GetUrl(UrlTemplateTaxonomies, parameters); } + public string GetLanguagesUrl(IEnumerable parameters) + { + return GetUrl(UrlTemplateLanguages, parameters); + } + private string GetUrl(string path, IEnumerable parameters) { if (parameters != null)