diff --git a/Contentful.Core.Tests/ContentfulManagementClientTests.cs b/Contentful.Core.Tests/ContentfulManagementClientTests.cs index 2f80803..384c936 100644 --- a/Contentful.Core.Tests/ContentfulManagementClientTests.cs +++ b/Contentful.Core.Tests/ContentfulManagementClientTests.cs @@ -6140,5 +6140,75 @@ public async Task CreateOrUpdateEntryWithConceptsInMetadata_ShouldCreateCorrectO Assert.Contains(@"""metadata"":{", requestContent); Assert.Contains(@"""concepts"":[{""sys"":{""type"":""Link"",""linkType"":""TaxonomyConcept"",""id"":""3kZdDUXy9n0l2Xi2cq8TPc""}}]", requestContent); } + + [Theory] + [InlineData("777", new string[] { "en-US" })] + [InlineData("abc", new string[] { "en-US", "sv-SE" })] + [InlineData("666", new string[] { "en-US", "fr-FR", "de-DE" })] + public async Task PublishingEntryLocalesShouldCallCorrectUrlAndPayload(string id, string[] locales) + { + //Arrange + _handler.Response = new HttpResponseMessage(); + var requestUrl = ""; + var versionHeader = ""; + var requestMethod = HttpMethod.Trace; + var contentSet = ""; + _handler.VerifyRequest = async (HttpRequestMessage request) => + { + requestMethod = request.Method; + requestUrl = request.RequestUri.ToString(); + versionHeader = request.Headers.GetValues("X-Contentful-Version").First(); + contentSet = await (request.Content as StringContent).ReadAsStringAsync(); + }; + _handler.Response = GetResponseFromFile(@"SampleEntryManagement.json"); + + //Act + await _client.PublishEntryLocales(id, 23, locales); + + //Assert + Assert.Equal(HttpMethod.Put, requestMethod); + Assert.Equal("23", versionHeader); + Assert.Equal($"https://api.contentful.com/spaces/666/entries/{id}/published", requestUrl); + Assert.Contains("add", contentSet); + foreach (var locale in locales) + { + Assert.Contains(locale, contentSet); + } + } + + [Theory] + [InlineData("777", new string[] { "en-US" })] + [InlineData("abc", new string[] { "en-US", "sv-SE" })] + [InlineData("666", new string[] { "en-US", "fr-FR", "de-DE" })] + public async Task UnPublishingEntryLocalesShouldCallCorrectUrlAndPayload(string id, string[] locales) + { + //Arrange + _handler.Response = new HttpResponseMessage(); + var requestUrl = ""; + var versionHeader = ""; + var requestMethod = HttpMethod.Trace; + var contentSet = ""; + _handler.VerifyRequest = async (HttpRequestMessage request) => + { + requestMethod = request.Method; + requestUrl = request.RequestUri.ToString(); + versionHeader = request.Headers.GetValues("X-Contentful-Version").First(); + contentSet = await (request.Content as StringContent).ReadAsStringAsync(); + }; + _handler.Response = GetResponseFromFile(@"SampleEntryManagement.json"); + + //Act + await _client.UnpublishEntryLocales(id, 23, locales); + + //Assert + Assert.Equal(HttpMethod.Put, requestMethod); + Assert.Equal("23", versionHeader); + Assert.Equal($"https://api.contentful.com/spaces/666/entries/{id}/published", requestUrl); + Assert.Contains("remove", contentSet); + foreach (var locale in locales) + { + Assert.Contains(locale, contentSet); + } + } } } diff --git a/Contentful.Core/ContentfulManagementClient.cs b/Contentful.Core/ContentfulManagementClient.cs index 80576e3..c946aa6 100644 --- a/Contentful.Core/ContentfulManagementClient.cs +++ b/Contentful.Core/ContentfulManagementClient.cs @@ -13,6 +13,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Newtonsoft.Json; namespace Contentful.Core { @@ -729,6 +730,90 @@ public async Task> UnpublishEntry(string entryId, int version, st return await GetObjectFromResponse>(res).ConfigureAwait(false); } + + /// + /// Publishes an entry with locale-based publishing by the specified id. + /// This method adds support for publishing specific locales + /// + /// The id of the entry. + /// The last known version of the entry. + /// The list of locale codes to be published. + /// The id of the space. Will default to the one set when creating the client. + /// The optional cancellation token to cancel the operation. + /// The response from the API serialized into + /// There was an error when communicating with the Contentful API. + /// The parameter was null or empty. + public async Task> PublishEntryLocales(string entryId, int version, string[] locales, string spaceId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(entryId)) + { + throw new ArgumentException(nameof(entryId)); + } + if (locales == null || locales.Length == 0) + { + throw new ArgumentException("Locales array cannot be null or empty.", nameof(locales)); + } + + var payload = new + { + add = new + { + fields = new Dictionary> + { + { "*", locales } + } + } + }; + + var jsonPayload = JsonConvert.SerializeObject(payload); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/vnd.contentful.management.v1+json"); + + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/published", content, cancellationToken, version).ConfigureAwait(false); + + return await GetObjectFromResponse>(res).ConfigureAwait(false); + } + + /// + /// UnPublishes an entry with locale-based publishing by the specified id. + /// This method adds support for publishing specific locales + /// + /// The id of the entry. + /// The last known version of the entry. + /// The list of locale codes to be Unpublished. + /// The id of the space. Will default to the one set when creating the client. + /// The optional cancellation token to cancel the operation. + /// The response from the API serialized into + /// There was an error when communicating with the Contentful API. + /// The parameter was null or empty. + public async Task> UnpublishEntryLocales(string entryId, int version, string[] locales, string spaceId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(entryId)) + { + throw new ArgumentException(nameof(entryId)); + } + if (locales == null || locales.Length == 0) + { + throw new ArgumentException("Locales array cannot be null or empty.", nameof(locales)); + } + + var payload = new + { + remove = new + { + fields = new Dictionary> + { + { "*", locales } + } + } + }; + + var jsonPayload = JsonConvert.SerializeObject(payload); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/vnd.contentful.management.v1+json"); + + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/published", content, cancellationToken, version).ConfigureAwait(false); + + return await GetObjectFromResponse>(res).ConfigureAwait(false); + } /// /// Archives an entry by the specified id. diff --git a/Contentful.Core/IContentfulManagementClient.cs b/Contentful.Core/IContentfulManagementClient.cs index 3415856..9d9f864 100644 --- a/Contentful.Core/IContentfulManagementClient.cs +++ b/Contentful.Core/IContentfulManagementClient.cs @@ -665,6 +665,18 @@ public interface IContentfulManagementClient /// The response from the API serialized into Task> PublishEntry(string entryId, int version, string spaceId = null, CancellationToken cancellationToken = default); + /// + /// Publishes an entry with locale-based publishing by the specified id. + /// This method adds support for publishing specific locales + /// + /// The id of the entry. + /// The last known version of the entry. + /// The list of locale codes to be published. + /// The id of the space. Will default to the one set when creating the client. + /// The optional cancellation token to cancel the operation. + /// The response from the API serialized into + Task> PublishEntryLocales(string entryId, int version, string[] locales, string spaceId = null, CancellationToken cancellationToken = default); + /// /// Unarchives an asset by the specified id. /// @@ -705,6 +717,20 @@ public interface IContentfulManagementClient /// The response from the API serialized into Task> UnpublishEntry(string entryId, int version, string spaceId = null, CancellationToken cancellationToken = default); + /// + /// UnPublishes an entry with locale-based publishing by the specified id. + /// This method adds support for publishing specific locales + /// + /// The id of the entry. + /// The last known version of the entry. + /// The list of locale codes to be Unpublished. + /// The id of the space. Will default to the one set when creating the client. + /// The optional cancellation token to cancel the operation. + /// The response from the API serialized into + /// There was an error when communicating with the Contentful API. + /// The parameter was null or empty. + Task> UnpublishEntryLocales(string entryId, int version, string[] locales, string spaceId = null, CancellationToken cancellationToken = default); + /// /// Updates a for a specific . /// @@ -1361,4 +1387,4 @@ Task CancelScheduledAction(string scheduledActionId, string env /// A representing the total number of concept schemes. Task GetTotalTaxonomyConceptSchemes(string organizationId, CancellationToken cancellationToken = default); } -} \ No newline at end of file +} diff --git a/Contentful.Core/Models/FieldStatus.cs b/Contentful.Core/Models/FieldStatus.cs new file mode 100644 index 0000000..f8112a6 --- /dev/null +++ b/Contentful.Core/Models/FieldStatus.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace Contentful.Core.Models; + +public class FieldStatus +{ + [JsonProperty(PropertyName = "*")] + public Dictionary Status { get; set; } +} + +public enum FieldStatusType +{ + [JsonProperty(PropertyName = "changed")] + Changed, + [JsonProperty(PropertyName = "draft")] + Draft, + [JsonProperty(PropertyName = "published")] + Published, + [JsonProperty(PropertyName = "deleted")] + Deleted, +} diff --git a/Contentful.Core/Models/SystemProperties.cs b/Contentful.Core/Models/SystemProperties.cs index 8e6a3a2..81ce6fd 100644 --- a/Contentful.Core/Models/SystemProperties.cs +++ b/Contentful.Core/Models/SystemProperties.cs @@ -107,6 +107,12 @@ public class SystemProperties : BaseSystemProperties /// [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Status Status { get; set; } + + /// + /// The link to the field status that the current object has. Used to get locale based publishing status. + /// + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public FieldStatus FieldStatus { get; set; } } }