diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6ea588b..a72377c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,6 +1,16 @@
name: "CI: Build and Test"
on:
+ push:
+ branches: [main]
+ paths:
+ - "**.cs"
+ - "**.tsx"
+ - "**.js"
+ - "**.csproj"
+ - "**.props"
+ - "**.targets"
+ - "**.sln"
pull_request:
branches: [main]
paths:
@@ -15,9 +25,20 @@ on:
- "**.sln"
jobs:
+ dotnet-format:
+ name: dotnet-format
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Run dotnet format
+ run: dotnet format --exclude ./examples/** --verify-no-changes
+
build_and_test:
name: Build and Test
runs-on: ubuntu-latest
+ needs: dotnet-format
defaults:
run:
shell: pwsh
@@ -29,10 +50,10 @@ jobs:
DOTNET_NOLOGO: 1
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemAddParams.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemAddParams.cs
index 40407da..df71987 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemAddParams.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemAddParams.cs
@@ -1,13 +1,13 @@
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Interface for synchronized content items.
-///
-public class ContentItemAddParams
-{
- public required ContentItemSynchronizationBase ContentItem { get; set; }
-
- public required string LanguageName { get; set; }
-
- public int UserID { get; set; }
-}
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Interface for synchronized content items.
+///
+public class ContentItemAddParams
+{
+ public required ContentItemSynchronizationBase ContentItem { get; set; }
+
+ public required string LanguageName { get; set; }
+
+ public int UserID { get; set; }
+}
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemServiceBase.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemServiceBase.cs
index 8b849b9..4beba1d 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemServiceBase.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemServiceBase.cs
@@ -1,130 +1,130 @@
-using CMS.ContentEngine;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Service for content items management
-///
-public class ContentItemServiceBase : IContentItemService
-{
- protected readonly IContentItemManagerFactory ContentItemManagerFactory;
-
- protected readonly IContentQueryExecutor ContentQueryExecutor;
-
- protected readonly IContentQueryResultMapper ContentQueryResultMapper;
-
-
- public ContentItemServiceBase(
- IContentItemManagerFactory contentItemManagerFactory,
- IContentQueryExecutor contentQueryExecutor,
- IContentQueryResultMapper contentQueryResultMapper)
- {
- ContentItemManagerFactory = contentItemManagerFactory;
- ContentQueryExecutor = contentQueryExecutor;
- ContentQueryResultMapper = contentQueryResultMapper;
- }
-
-
- ///
- public async Task AddContentItem(ContentItemAddParams addParams)
- {
- ArgumentNullException.ThrowIfNull(addParams);
-
- var createParams = new CreateContentItemParameters(
- addParams.ContentItem.ContentTypeName,
- addParams.ContentItem.GenerateCodeName(),
- addParams.ContentItem.DisplayName,
- addParams.LanguageName);
- var itemData = new ContentItemData(addParams.ContentItem.ToDict());
-
- var contentItemManager = ContentItemManagerFactory.Create(addParams.UserID);
- int itemID = await contentItemManager.Create(createParams, itemData);
- await contentItemManager.TryPublish(itemID, addParams.LanguageName);
-
- return itemID;
- }
-
-
- ///
- public async Task UpdateContentItem(ContentItemUpdateParams updateParams)
- {
- var contentItemManager = ContentItemManagerFactory.Create(updateParams.UserID);
- var versionStatus = updateParams.VersionStatus;
-
- // If content item version is not draft, create draft in order to edit it
- if (versionStatus != VersionStatus.Draft &&
- versionStatus != VersionStatus.InitialDraft &&
- !await contentItemManager.TryCreateDraft(updateParams.ContentItemID, updateParams.LanguageName))
- {
- return false;
- }
-
- var itemData = new ContentItemData(updateParams.ContentItemParams);
- if (!await contentItemManager.TryUpdateDraft(updateParams.ContentItemID, updateParams.LanguageName, itemData))
- {
- return false;
- }
-
- return versionStatus switch
- {
- VersionStatus.Published => await contentItemManager.TryPublish(updateParams.ContentItemID, updateParams.LanguageName),
- VersionStatus.Archived => await contentItemManager.TryArchive(updateParams.ContentItemID, updateParams.LanguageName),
- VersionStatus.InitialDraft => true,
- VersionStatus.Draft => true,
- _ => true,
- };
- }
-
-
- ///
- public async Task> GetContentItems(string contentType, Action queryParams)
- where T : IContentItemFieldsSource, new()
- {
- var builder = new ContentItemQueryBuilder()
- .ForContentType(contentType, queryParams);
-
- return await ContentQueryExecutor.GetResult(builder, ContentQueryResultMapper.Map);
- }
-
-
- ///
- public async Task> GetContentItems(string contentType)
- where T : IContentItemFieldsSource, new() => await GetContentItems(contentType, 0);
-
-
- ///
- public async Task> GetContentItems(string contentType, int linkedItemsLevel)
- where T : IContentItemFieldsSource, new()
- {
- var builder = new ContentItemQueryBuilder()
- .ForContentType(contentType, config => config.WithLinkedItems(linkedItemsLevel));
-
- return await ContentQueryExecutor.GetResult(builder, ContentQueryResultMapper.Map);
- }
-
-
- ///
- public async Task DeleteContentItem(int contentItemID, string languageName, int userID)
- {
- var contentItemManager = ContentItemManagerFactory.Create(userID);
- await contentItemManager.Delete(contentItemID, languageName);
- }
-
-
- ///
- public async Task DeleteContentItems(IEnumerable contentItemIDs, string languageName, int userID)
- {
- if (!contentItemIDs.Any())
- {
- return;
- }
-
- var contentItemManager = ContentItemManagerFactory.Create(userID);
-
- foreach (int contentItemID in contentItemIDs)
- {
- await contentItemManager.Delete(contentItemID, languageName);
- }
- }
-}
-
+using CMS.ContentEngine;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Service for content items management
+///
+public class ContentItemServiceBase : IContentItemService
+{
+ protected readonly IContentItemManagerFactory ContentItemManagerFactory;
+
+ protected readonly IContentQueryExecutor ContentQueryExecutor;
+
+ protected readonly IContentQueryResultMapper ContentQueryResultMapper;
+
+
+ public ContentItemServiceBase(
+ IContentItemManagerFactory contentItemManagerFactory,
+ IContentQueryExecutor contentQueryExecutor,
+ IContentQueryResultMapper contentQueryResultMapper)
+ {
+ ContentItemManagerFactory = contentItemManagerFactory;
+ ContentQueryExecutor = contentQueryExecutor;
+ ContentQueryResultMapper = contentQueryResultMapper;
+ }
+
+
+ ///
+ public async Task AddContentItem(ContentItemAddParams addParams)
+ {
+ ArgumentNullException.ThrowIfNull(addParams);
+
+ var createParams = new CreateContentItemParameters(
+ addParams.ContentItem.ContentTypeName,
+ addParams.ContentItem.GenerateCodeName(),
+ addParams.ContentItem.DisplayName,
+ addParams.LanguageName);
+ var itemData = new ContentItemData(addParams.ContentItem.ToDict());
+
+ var contentItemManager = ContentItemManagerFactory.Create(addParams.UserID);
+ int itemID = await contentItemManager.Create(createParams, itemData);
+ await contentItemManager.TryPublish(itemID, addParams.LanguageName);
+
+ return itemID;
+ }
+
+
+ ///
+ public async Task UpdateContentItem(ContentItemUpdateParams updateParams)
+ {
+ var contentItemManager = ContentItemManagerFactory.Create(updateParams.UserID);
+ var versionStatus = updateParams.VersionStatus;
+
+ // If content item version is not draft, create draft in order to edit it
+ if (versionStatus != VersionStatus.Draft &&
+ versionStatus != VersionStatus.InitialDraft &&
+ !await contentItemManager.TryCreateDraft(updateParams.ContentItemID, updateParams.LanguageName))
+ {
+ return false;
+ }
+
+ var itemData = new ContentItemData(updateParams.ContentItemParams);
+ if (!await contentItemManager.TryUpdateDraft(updateParams.ContentItemID, updateParams.LanguageName, itemData))
+ {
+ return false;
+ }
+
+ return versionStatus switch
+ {
+ VersionStatus.Published => await contentItemManager.TryPublish(updateParams.ContentItemID, updateParams.LanguageName),
+ VersionStatus.Archived => await contentItemManager.TryArchive(updateParams.ContentItemID, updateParams.LanguageName),
+ VersionStatus.InitialDraft => true,
+ VersionStatus.Draft => true,
+ _ => true,
+ };
+ }
+
+
+ ///
+ public async Task> GetContentItems(string contentType, Action queryParams)
+ where T : IContentItemFieldsSource, new()
+ {
+ var builder = new ContentItemQueryBuilder()
+ .ForContentType(contentType, queryParams);
+
+ return await ContentQueryExecutor.GetResult(builder, ContentQueryResultMapper.Map);
+ }
+
+
+ ///
+ public async Task> GetContentItems(string contentType)
+ where T : IContentItemFieldsSource, new() => await GetContentItems(contentType, 0);
+
+
+ ///
+ public async Task> GetContentItems(string contentType, int linkedItemsLevel)
+ where T : IContentItemFieldsSource, new()
+ {
+ var builder = new ContentItemQueryBuilder()
+ .ForContentType(contentType, config => config.WithLinkedItems(linkedItemsLevel));
+
+ return await ContentQueryExecutor.GetResult(builder, ContentQueryResultMapper.Map);
+ }
+
+
+ ///
+ public async Task DeleteContentItem(int contentItemID, string languageName, int userID)
+ {
+ var contentItemManager = ContentItemManagerFactory.Create(userID);
+ await contentItemManager.Delete(contentItemID, languageName);
+ }
+
+
+ ///
+ public async Task DeleteContentItems(IEnumerable contentItemIDs, string languageName, int userID)
+ {
+ if (!contentItemIDs.Any())
+ {
+ return;
+ }
+
+ var contentItemManager = ContentItemManagerFactory.Create(userID);
+
+ foreach (int contentItemID in contentItemIDs)
+ {
+ await contentItemManager.Delete(contentItemID, languageName);
+ }
+ }
+}
+
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemSynchronizationBase.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemSynchronizationBase.cs
index 8fd2c1d..36b704b 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemSynchronizationBase.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemSynchronizationBase.cs
@@ -1,123 +1,123 @@
-using System.Reflection;
-using System.Text;
-
-using CMS.ContentEngine;
-using CMS.Helpers;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Synchronization base for content items.
-///
-public abstract class ContentItemSynchronizationBase
-{
- private const string CODE_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
- private const int CODE_LENGTH = 8;
- private const int NAME_LENGTH = 100;
-
- protected abstract string DisplayNameInternal { get; }
-
-
- public abstract string ContentTypeName { get; }
-
-
- ///
- /// Content item display name with max length of .
- ///
- public string DisplayName =>
- DisplayNameInternal.Length > NAME_LENGTH ? (DisplayNameInternal?[..NAME_LENGTH] ?? string.Empty) : DisplayNameInternal;
-
-
- ///
- /// Generate dictionary where keys are property names and values are property values.
- /// properties are excluded.
- ///
- /// Dictionary where key = property name and value = property value.
- public virtual Dictionary ToDict()
- {
- var baseProperties = typeof(ContentItemSynchronizationBase)
- .GetProperties(BindingFlags.Public | BindingFlags.Instance)
- .Select(p => p.Name);
-
- var type = GetType();
-
- // Get only properties that are not from IContentItemBase
- var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
- .Where(p => !baseProperties.Contains(p.Name));
-
- Dictionary result = [];
-
- foreach (var property in properties)
- {
- string propertyName = property.Name;
- object? propertyValue = property.GetValue(this);
-
- result.Add(propertyName, propertyValue);
- }
-
- return result;
- }
-
-
-#pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved
- ///
- /// Get content item code name or generate if does not exist.
- /// Generated code name consists of that is transformed to code name using
- /// and random 8 characters long alphanumeric string. Maximum length will be
- ///
- ///
- /// Generated code name
- ///
-#pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved
- public string GenerateCodeName()
- {
- var random = Random.Shared;
-
- string? codeName = ValidationHelper.GetCodeName(DisplayName);
-
- if (codeName.Length + CODE_LENGTH >= NAME_LENGTH)
- {
- codeName = codeName[..(NAME_LENGTH - CODE_LENGTH - 1)];
- }
-
- var sb = new StringBuilder(codeName);
- sb.Append('-');
- for (int i = 0; i < CODE_LENGTH; i++)
- {
- sb.Append(CODE_CHARS[random.Next(CODE_CHARS.Length)]);
- }
-
- return sb.ToString();
- }
-
-
- protected bool ReferenceModified(IEnumerable contentItems, IEnumerable contentItemReferences)
- {
- if (contentItems.Count() != contentItemReferences.Count())
- {
- return true;
- }
-
- for (int i = 0; i < contentItemReferences.Count(); i++)
- {
- var referenceObject = contentItemReferences.ElementAtOrDefault(i);
- var contentItem = contentItems.ElementAtOrDefault(i);
-
- if (referenceObject?.Identifier != contentItem?.SystemFields?.ContentItemGUID)
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- protected void SetPropsIfDiff(T source, T dest, string key, Dictionary props)
- {
- if ((source is null && dest is not null) || (source is not null && !source.Equals(dest)))
- {
- props.TryAdd(key, dest);
- }
- }
-}
+using System.Reflection;
+using System.Text;
+
+using CMS.ContentEngine;
+using CMS.Helpers;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Synchronization base for content items.
+///
+public abstract class ContentItemSynchronizationBase
+{
+ private const string CODE_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
+ private const int CODE_LENGTH = 8;
+ private const int NAME_LENGTH = 100;
+
+ protected abstract string DisplayNameInternal { get; }
+
+
+ public abstract string ContentTypeName { get; }
+
+
+ ///
+ /// Content item display name with max length of .
+ ///
+ public string DisplayName =>
+ DisplayNameInternal.Length > NAME_LENGTH ? (DisplayNameInternal?[..NAME_LENGTH] ?? string.Empty) : DisplayNameInternal;
+
+
+ ///
+ /// Generate dictionary where keys are property names and values are property values.
+ /// properties are excluded.
+ ///
+ /// Dictionary where key = property name and value = property value.
+ public virtual Dictionary ToDict()
+ {
+ var baseProperties = typeof(ContentItemSynchronizationBase)
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Select(p => p.Name);
+
+ var type = GetType();
+
+ // Get only properties that are not from IContentItemBase
+ var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
+ .Where(p => !baseProperties.Contains(p.Name));
+
+ Dictionary result = [];
+
+ foreach (var property in properties)
+ {
+ string propertyName = property.Name;
+ object? propertyValue = property.GetValue(this);
+
+ result.Add(propertyName, propertyValue);
+ }
+
+ return result;
+ }
+
+
+#pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved
+ ///
+ /// Get content item code name or generate if does not exist.
+ /// Generated code name consists of that is transformed to code name using
+ /// and random 8 characters long alphanumeric string. Maximum length will be
+ ///
+ ///
+ /// Generated code name
+ ///
+#pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved
+ public string GenerateCodeName()
+ {
+ var random = Random.Shared;
+
+ string? codeName = ValidationHelper.GetCodeName(DisplayName);
+
+ if (codeName.Length + CODE_LENGTH >= NAME_LENGTH)
+ {
+ codeName = codeName[..(NAME_LENGTH - CODE_LENGTH - 1)];
+ }
+
+ var sb = new StringBuilder(codeName);
+ sb.Append('-');
+ for (int i = 0; i < CODE_LENGTH; i++)
+ {
+ sb.Append(CODE_CHARS[random.Next(CODE_CHARS.Length)]);
+ }
+
+ return sb.ToString();
+ }
+
+
+ protected bool ReferenceModified(IEnumerable contentItems, IEnumerable contentItemReferences)
+ {
+ if (contentItems.Count() != contentItemReferences.Count())
+ {
+ return true;
+ }
+
+ for (int i = 0; i < contentItemReferences.Count(); i++)
+ {
+ var referenceObject = contentItemReferences.ElementAtOrDefault(i);
+ var contentItem = contentItems.ElementAtOrDefault(i);
+
+ if (referenceObject?.Identifier != contentItem?.SystemFields?.ContentItemGUID)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ protected void SetPropsIfDiff(T source, T dest, string key, Dictionary props)
+ {
+ if ((source is null && dest is not null) || (source is not null && !source.Equals(dest)))
+ {
+ props.TryAdd(key, dest);
+ }
+ }
+}
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemUpdateParams.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemUpdateParams.cs
index 2e94f52..cb5b66e 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemUpdateParams.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ContentItemUpdateParams.cs
@@ -1,19 +1,19 @@
-using CMS.ContentEngine;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Parameters for content item update in synchronization.
-///
-public class ContentItemUpdateParams
-{
- public required Dictionary ContentItemParams { get; set; }
-
- public required int ContentItemID { get; set; }
-
- public required string LanguageName { get; set; }
-
- public required int UserID { get; set; }
-
- public required VersionStatus VersionStatus { get; set; }
-}
+using CMS.ContentEngine;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Parameters for content item update in synchronization.
+///
+public class ContentItemUpdateParams
+{
+ public required Dictionary ContentItemParams { get; set; }
+
+ public required int ContentItemID { get; set; }
+
+ public required string LanguageName { get; set; }
+
+ public required int UserID { get; set; }
+
+ public required VersionStatus VersionStatus { get; set; }
+}
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemBase.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemBase.cs
index 2b11a8d..56854d6 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemBase.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemBase.cs
@@ -1,17 +1,17 @@
-using CMS.ContentEngine;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Interface for synchronized content items.
-///
-public interface IContentItemBase : IContentItemFieldsSource
-{
- string ContentTypeName { get; }
-
- string DisplayName { get; }
-
- string ShopifyObjectID { get; }
-
- int ContentItemIdentifier { get; }
-}
+using CMS.ContentEngine;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Interface for synchronized content items.
+///
+public interface IContentItemBase : IContentItemFieldsSource
+{
+ string ContentTypeName { get; }
+
+ string DisplayName { get; }
+
+ string ShopifyObjectID { get; }
+
+ int ContentItemIdentifier { get; }
+}
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemService.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemService.cs
index d62f550..fe96f9e 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemService.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IContentItemService.cs
@@ -1,77 +1,77 @@
-using CMS.ContentEngine;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Interface for content items management
-///
-public interface IContentItemService
-{
- ///
- /// Add and publish content item.
- ///
- ///
- /// ID of created content item.
- Task AddContentItem(ContentItemAddParams addParams);
-
-
- ///
- /// Get content items of given content type and query params.
- ///
- ///
- ///
- ///
- /// Collection of content items.
- Task> GetContentItems(string contentType, Action queryParams)
- where T : IContentItemFieldsSource, new();
-
-
- ///
- /// Get content items of given content type.
- ///
- ///
- ///
- /// Collection of content items.
- Task> GetContentItems(string contentType)
- where T : IContentItemFieldsSource, new();
-
-
- ///
- /// Get content items of given content type.
- ///
- ///
- ///
- /// >Max. level for linked items
- /// Collection of content items.
- Task> GetContentItems(string contentType, int linkedItemsLevel)
- where T : IContentItemFieldsSource, new();
-
-
- ///
- /// Updates content item.
- ///
- ///
- /// True when update succeeds, else False.
- Task UpdateContentItem(ContentItemUpdateParams updateParams);
-
-
- ///
- /// Deletes content item.
- ///
- ///
- ///
- ///
- ///
- Task DeleteContentItem(int contentItemID, string languageName, int userID);
-
-
- ///
- /// Delete content items.
- ///
- /// Content type IDs
- ///
- ///
- ///
- Task DeleteContentItems(IEnumerable contentItemIDs, string languageName, int userID);
-}
-
+using CMS.ContentEngine;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Interface for content items management
+///
+public interface IContentItemService
+{
+ ///
+ /// Add and publish content item.
+ ///
+ ///
+ /// ID of created content item.
+ Task AddContentItem(ContentItemAddParams addParams);
+
+
+ ///
+ /// Get content items of given content type and query params.
+ ///
+ ///
+ ///
+ ///
+ /// Collection of content items.
+ Task> GetContentItems(string contentType, Action queryParams)
+ where T : IContentItemFieldsSource, new();
+
+
+ ///
+ /// Get content items of given content type.
+ ///
+ ///
+ ///
+ /// Collection of content items.
+ Task> GetContentItems(string contentType)
+ where T : IContentItemFieldsSource, new();
+
+
+ ///
+ /// Get content items of given content type.
+ ///
+ ///
+ ///
+ /// >Max. level for linked items
+ /// Collection of content items.
+ Task> GetContentItems(string contentType, int linkedItemsLevel)
+ where T : IContentItemFieldsSource, new();
+
+
+ ///
+ /// Updates content item.
+ ///
+ ///
+ /// True when update succeeds, else False.
+ Task UpdateContentItem(ContentItemUpdateParams updateParams);
+
+
+ ///
+ /// Deletes content item.
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task DeleteContentItem(int contentItemID, string languageName, int userID);
+
+
+ ///
+ /// Delete content items.
+ ///
+ /// Content type IDs
+ ///
+ ///
+ ///
+ Task DeleteContentItems(IEnumerable contentItemIDs, string languageName, int userID);
+}
+
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IItemIdentifier.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IItemIdentifier.cs
index 1a1aeb5..9f114e2 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IItemIdentifier.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/IItemIdentifier.cs
@@ -1,13 +1,13 @@
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Interface to set external identifier for api objects.
-///
-/// External ID type.
-public interface IItemIdentifier
-{
- ///
- /// External identifier.
- ///
- public TType ExternalId { get; }
-}
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Interface to set external identifier for api objects.
+///
+/// External ID type.
+public interface IItemIdentifier
+{
+ ///
+ /// External identifier.
+ ///
+ public TType ExternalId { get; }
+}
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ISynchronizationItem.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ISynchronizationItem.cs
index e0b9400..0324544 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ISynchronizationItem.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/ISynchronizationItem.cs
@@ -1,40 +1,40 @@
-using CMS.ContentEngine;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-public interface ISynchronizationItem
- where TContentItem : IContentItemBase, new()
-{
- ///
- /// Fills modifiedProps with modified properties compared to contentItem.
- ///
- ///
- ///
- /// True if any property was modified. Otherwise False.
- public bool GetModifiedProperties(TContentItem contentItem, out Dictionary modifiedProps);
-}
-
-
-///
-/// Interface for synchronization between data in Dto and content items.
-///
-///
-///
-public interface ISynchronizationItem
- where TDto : class
- where TContentItem : IContentItemFieldsSource
-{
- ///
- /// Dto item, typically object from Ecommerce platform API
- ///
- public TDto Item { get; set; }
-
-
- ///
- /// Fills modifiedProps with modified properties compared to contentItem.
- ///
- ///
- ///
- /// True if any property was modified. Otherwise False.
- bool GetModifiedProperties(TContentItem contentItem, out Dictionary modifiedProps);
-}
+using CMS.ContentEngine;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+public interface ISynchronizationItem
+ where TContentItem : IContentItemBase, new()
+{
+ ///
+ /// Fills modifiedProps with modified properties compared to contentItem.
+ ///
+ ///
+ ///
+ /// True if any property was modified. Otherwise False.
+ public bool GetModifiedProperties(TContentItem contentItem, out Dictionary modifiedProps);
+}
+
+
+///
+/// Interface for synchronization between data in Dto and content items.
+///
+///
+///
+public interface ISynchronizationItem
+ where TDto : class
+ where TContentItem : IContentItemFieldsSource
+{
+ ///
+ /// Dto item, typically object from Ecommerce platform API
+ ///
+ public TDto Item { get; set; }
+
+
+ ///
+ /// Fills modifiedProps with modified properties compared to contentItem.
+ ///
+ ///
+ ///
+ /// True if any property was modified. Otherwise False.
+ bool GetModifiedProperties(TContentItem contentItem, out Dictionary modifiedProps);
+}
diff --git a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/SynchronizationServiceCommon.cs b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/SynchronizationServiceCommon.cs
index 8d871ed..83af7c9 100644
--- a/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/SynchronizationServiceCommon.cs
+++ b/src/Kentico.Xperience.Ecommerce.Common/ContentItemSynchronization/SynchronizationServiceCommon.cs
@@ -1,82 +1,82 @@
-using System.Net.Mime;
-
-using CMS.ContentEngine;
-using CMS.Core;
-
-using Path = CMS.IO.Path;
-
-namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
-
-///
-/// Common service base functionality for synchronization of content items.
-///
-///
-public abstract class SynchronizationServiceCommon(IHttpClientFactory httpClientFactory)
-{
- protected (IEnumerable ToCreate, IEnumerable<(TStoreItem StoreItem, TContentItem ContentItem)> ToUpdate,
- IEnumerable ToDelete)
- ClassifyItems(IEnumerable storeItems,
- IEnumerable existingItems)
- where TStoreItem : IItemIdentifier
- where TContentItem : IItemIdentifier
- {
- var existingLookup = existingItems.ToLookup(item => item.ExternalId);
- var storeLookup = storeItems.ToLookup(item => item.ExternalId);
-
- var toCreate = storeItems.Where(storeItem => !existingLookup.Contains(storeItem.ExternalId))
- .ToList();
-
- var toUpdate = storeItems.SelectMany(storeItem => existingLookup[storeItem.ExternalId],
- (storeItem, existingItem) => (storeItem, existingItem))
- .ToList();
-
- var toDelete = existingItems.Where(p => !storeLookup.Contains(p.ExternalId)).ToList();
-
- return (toCreate, toUpdate, toDelete);
- }
-
-
- protected async Task CreateAssetMetadata(string url, string name)
- {
- byte[] bytes;
- string? contentType;
- using (var client = httpClientFactory.CreateClient())
- {
- var response = await client.GetAsync(url);
- response.EnsureSuccessStatusCode();
- bytes = await response.Content.ReadAsByteArrayAsync();
- contentType = response.Content.Headers.ContentType?.MediaType;
- }
-
- long length = bytes.LongLength;
- var dataWrapper = new BinaryDataWrapper(bytes);
- var fileSource = new ContentItemAssetStreamSource(cancellationToken => Task.FromResult(dataWrapper.Stream));
- string extension = Path.GetExtension(name);
- if (string.IsNullOrWhiteSpace(extension))
- {
- extension = GetExtension(contentType);
- name += extension;
- }
-
- var assetMetadata = new ContentItemAssetMetadata()
- {
- Extension = extension,
- Identifier = Guid.NewGuid(),
- LastModified = DateTime.Now,
- Name = name,
- Size = length
- };
-
- return new ContentItemAssetMetadataWithSource(fileSource, assetMetadata);
- }
-
- private static string GetExtension(string? contentType) =>
- contentType switch
- {
- MediaTypeNames.Image.Jpeg => ".jpg",
- MediaTypeNames.Image.Png => ".png",
- MediaTypeNames.Image.Webp => ".webp",
- MediaTypeNames.Image.Avif => ".avif",
- _ => string.Empty
- };
-}
+using System.Net.Mime;
+
+using CMS.ContentEngine;
+using CMS.Core;
+
+using Path = CMS.IO.Path;
+
+namespace Kentico.Xperience.Ecommerce.Common.ContentItemSynchronization;
+
+///
+/// Common service base functionality for synchronization of content items.
+///
+///
+public abstract class SynchronizationServiceCommon(IHttpClientFactory httpClientFactory)
+{
+ protected (IEnumerable ToCreate, IEnumerable<(TStoreItem StoreItem, TContentItem ContentItem)> ToUpdate,
+ IEnumerable ToDelete)
+ ClassifyItems(IEnumerable storeItems,
+ IEnumerable existingItems)
+ where TStoreItem : IItemIdentifier
+ where TContentItem : IItemIdentifier
+ {
+ var existingLookup = existingItems.ToLookup(item => item.ExternalId);
+ var storeLookup = storeItems.ToLookup(item => item.ExternalId);
+
+ var toCreate = storeItems.Where(storeItem => !existingLookup.Contains(storeItem.ExternalId))
+ .ToList();
+
+ var toUpdate = storeItems.SelectMany(storeItem => existingLookup[storeItem.ExternalId],
+ (storeItem, existingItem) => (storeItem, existingItem))
+ .ToList();
+
+ var toDelete = existingItems.Where(p => !storeLookup.Contains(p.ExternalId)).ToList();
+
+ return (toCreate, toUpdate, toDelete);
+ }
+
+
+ protected async Task CreateAssetMetadata(string url, string name)
+ {
+ byte[] bytes;
+ string? contentType;
+ using (var client = httpClientFactory.CreateClient())
+ {
+ var response = await client.GetAsync(url);
+ response.EnsureSuccessStatusCode();
+ bytes = await response.Content.ReadAsByteArrayAsync();
+ contentType = response.Content.Headers.ContentType?.MediaType;
+ }
+
+ long length = bytes.LongLength;
+ var dataWrapper = new BinaryDataWrapper(bytes);
+ var fileSource = new ContentItemAssetStreamSource(cancellationToken => Task.FromResult(dataWrapper.Stream));
+ string extension = Path.GetExtension(name);
+ if (string.IsNullOrWhiteSpace(extension))
+ {
+ extension = GetExtension(contentType);
+ name += extension;
+ }
+
+ var assetMetadata = new ContentItemAssetMetadata()
+ {
+ Extension = extension,
+ Identifier = Guid.NewGuid(),
+ LastModified = DateTime.Now,
+ Name = name,
+ Size = length
+ };
+
+ return new ContentItemAssetMetadataWithSource(fileSource, assetMetadata);
+ }
+
+ private static string GetExtension(string? contentType) =>
+ contentType switch
+ {
+ MediaTypeNames.Image.Jpeg => ".jpg",
+ MediaTypeNames.Image.Png => ".png",
+ MediaTypeNames.Image.Webp => ".webp",
+ MediaTypeNames.Image.Avif => ".avif",
+ _ => string.Empty
+ };
+}