diff --git a/Configurations/Entities/XStringEntityConfiguration.cs b/Configurations/Entities/XStringEntityConfiguration.cs new file mode 100644 index 0000000..f5f5f7f --- /dev/null +++ b/Configurations/Entities/XStringEntityConfiguration.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xDataService.Providers; +using xStringService.Models.Entities; + +namespace xStringService.Configurations.Entities +{ + public class XStringEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { } + } +} \ No newline at end of file diff --git a/DataHelper/Events/XStringEvents.cs b/DataHelper/Events/XStringEvents.cs deleted file mode 100644 index 06d0f8d..0000000 --- a/DataHelper/Events/XStringEvents.cs +++ /dev/null @@ -1,9 +0,0 @@ -using xDataService.Providers; -using xStringService.Interfaces.Entities; -using xStringService.Models.Entities; - -namespace xStringService.DataHelper.Events -{ - public class XStringEvents : XBaseRepositoryEvents, IXStringEvents - {} -} \ No newline at end of file diff --git a/Extensions/XModelExtensions.cs b/Extensions/XModelExtensions.cs index 9198007..5a2ec58 100644 --- a/Extensions/XModelExtensions.cs +++ b/Extensions/XModelExtensions.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using System.Linq; using xCommons.Extensions; diff --git a/Hubs/XStringEntityHub.cs b/Hubs/XStringEntityHub.cs deleted file mode 100644 index 2f34dac..0000000 --- a/Hubs/XStringEntityHub.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.Extensions.Logging; -using xPushService.Base; -using xStringService.Models.Entities; - -namespace xStringService.Hubs -{ - public class XStringEntityHub : XBaseEntityHub - { - // - #region Constructor ... - public XStringEntityHub(ILogger logger) : base(logger) - { } - #endregion - } -} \ No newline at end of file diff --git a/Interfaces/Dtos/IXStringDtoHub.cs b/Interfaces/Dtos/IXStringDtoHub.cs new file mode 100644 index 0000000..ad0b643 --- /dev/null +++ b/Interfaces/Dtos/IXStringDtoHub.cs @@ -0,0 +1,9 @@ +using xPushService.Interfaces; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Dtos +{ + public interface IXStringDtoHub : IXBaseDtoHub + { } +} \ No newline at end of file diff --git a/Interfaces/Dtos/IXStringRepositoryService.cs b/Interfaces/Dtos/IXStringRepositoryService.cs new file mode 100644 index 0000000..14a4c42 --- /dev/null +++ b/Interfaces/Dtos/IXStringRepositoryService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xModels.Dtos; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Dtos +{ + public interface IXStringRepositoryService : IXBaseRepositoryService + { } +} \ No newline at end of file diff --git a/Interfaces/Dtos/IXStringServiceProvider.cs b/Interfaces/Dtos/IXStringServiceProvider.cs new file mode 100644 index 0000000..6987c86 --- /dev/null +++ b/Interfaces/Dtos/IXStringServiceProvider.cs @@ -0,0 +1,302 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xCommons.Configurations; +using xModels.Dtos; +using xPushService.Interfaces; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; +using xStringService.Providers.Dtos; + +namespace xStringService.Interfaces.Dtos +{ + public interface IXStringServiceProvider : IXBaseDtoProvider + { + /// + /// Application Configuration ... + /// + XAppConfiguration AppConfiguration { get; } + + // + #region Retrievers ... + /// + /// Retrieve all Exists Languages ... + /// + /// + /// + Task> GetLanguages( + CancellationToken cancellationToken = default + ); + + /// + /// Check Specified Resource Exists or not ... + /// + /// + /// + /// + /// + Task IsResourceExists( + string resource, + string language = null, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Specified Resource ... + /// + /// + /// + /// + /// + Task Get( + string resource, + string language = null, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Specified Translation of Specified Resource ... + /// + /// + /// + /// + /// + Task GetResourceValue( + string resource, + string language = null, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve an Specified Resource Items ... + /// + /// + /// + /// + Task> GetResources( + string resource, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Specified Resource Items as XResourceDto Presentation ... + /// + /// + /// + /// + Task GetResource( + string resource, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Query ... + /// + /// Query Resource IDs ... + /// + /// + /// + /// + Task> QueryResourceIds( + XQuery query, + CancellationToken cancellationToken = default + ); + + /// + /// Query Specified Language Resources ... + /// + /// + /// + /// + /// + Task> QueryLanguageResources( + XQuery query, + string language = null, + CancellationToken cancellationToken = default + ); + + /// + /// Query Locale Resources ... + /// + /// + /// + /// + /// + Task> QueryLocaleResources( + XQuery query, + string language = null, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Add/Update Actions ... + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + /// + /// + Task Add( + string resource, + string value, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Update Resource ... + /// + /// + /// + /// + /// + /// + /// + Task Update( + string resource, + string value, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Or Update Resource ... + /// + /// + /// + /// + /// + /// + /// + Task AddOrUpdate( + string resource, + string value, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Specified Locale Resource ... + /// + /// + /// + /// + /// + /// + Task AddByLocaleResource( + XLocaleResourceDto item, + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Update Specified Locale Resource ... + /// + /// + /// + /// + /// + /// + Task UpdateByLocaleResource( + XLocaleResourceDto item, + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Or Update Resource By Locale ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateByLocaleResource( + XLocaleResourceDto item, + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Or Update all XResourceDto(s) Locales ... + /// + /// + /// + /// + /// + Task> AddByResource( + XResourceDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Remove Actions ... + /// + /// Remove all Specified Language's Resources ... + /// + /// + /// + /// + /// + Task RemoveLanguageResources( + string language, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove all Specified Resource Ids instances ... + /// + /// + /// + /// + /// + Task> RemoveResource( + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + /// + /// + Task Remove( + string resource, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove all Resource of Specified XResourceDto ... + /// + /// + /// + /// + /// + Task RemoveByResource( + XResourceDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/Entities/IXStringEntityHub.cs b/Interfaces/Entities/IXStringEntityHub.cs new file mode 100644 index 0000000..8ffc7f2 --- /dev/null +++ b/Interfaces/Entities/IXStringEntityHub.cs @@ -0,0 +1,8 @@ +using xPushService.Interfaces; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Entities +{ + public interface IXStringEntityHub : IXBaseEntityHub + { } +} \ No newline at end of file diff --git a/Interfaces/Entities/IXStringEvents.cs b/Interfaces/Entities/IXStringKeyGenerator.cs similarity index 63% rename from Interfaces/Entities/IXStringEvents.cs rename to Interfaces/Entities/IXStringKeyGenerator.cs index 4f6b4da..6123f45 100644 --- a/Interfaces/Entities/IXStringEvents.cs +++ b/Interfaces/Entities/IXStringKeyGenerator.cs @@ -3,6 +3,6 @@ using xStringService.Models.Entities; namespace xStringService.Interfaces.Entities { - public interface IXStringEvents : IXBaseRepositoryEvents + public interface IXStringKeyGenerator : IXKeyGenerator { } } \ No newline at end of file diff --git a/Interfaces/Entities/IXStringRepositoryEvents.cs b/Interfaces/Entities/IXStringRepositoryEvents.cs new file mode 100644 index 0000000..5c69c87 --- /dev/null +++ b/Interfaces/Entities/IXStringRepositoryEvents.cs @@ -0,0 +1,8 @@ +using xDataService.Interfaces; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Entities +{ + public interface IXStringRepositoryEvents : IXBaseRepositoryEvents + { } +} \ No newline at end of file diff --git a/Interfaces/Entities/IXStringRepositoryProvider.cs b/Interfaces/Entities/IXStringRepositoryProvider.cs new file mode 100644 index 0000000..cf3fa52 --- /dev/null +++ b/Interfaces/Entities/IXStringRepositoryProvider.cs @@ -0,0 +1,9 @@ +using xPushService.Interfaces; +using xStringService.Models.Entities; +using xStringService.Providers.Entities; + +namespace xStringService.Interfaces.Entities +{ + public interface IXStringRepositoryProvider : IXBaseEntityProviderr + { } +} \ No newline at end of file diff --git a/Interfaces/IXBaseStringResourceProvider.cs b/Interfaces/IXBaseStringResourceProvider.cs new file mode 100644 index 0000000..444832a --- /dev/null +++ b/Interfaces/IXBaseStringResourceProvider.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xCommons.Configurations; +using xModels.Dtos; +using xStringService.Interfaces.Dtos; +using xStringService.Models.Dtos; + +namespace xStringService.Interfaces +{ + /// + /// a Base Class for Handling Resources Based on Specified Types on + /// String Resources Use ... + /// such as: + /// - Terms and Conditions; + /// - Contents; + /// - News; + /// - etc ... + /// + public interface IXBaseStringResourceProvider + { + // + #region Props ... + string Prefix { get; } + IXStringServiceProvider Provider { get; } + XAppConfiguration AppConfiguration { get; } + #endregion + + // + #region Actions ... + /// + /// Prepare Resource Title by Given Data ... + /// + /// + /// + string GetResourceTitle(string suffix); + + /// + /// Add Specified Locales ... + /// + /// + /// + /// + /// + /// + Task> Add( + string suffix, + IEnumerable locales, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Or Update Specified Locals ... + /// + /// + /// + /// + /// + /// + Task> AddOrUpdate( + string resource, + IEnumerable locales, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Get Specified Locale ... + /// + /// + /// + /// + /// + Task GetLocale( + string suffix, + string language = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + /// + Task AddResource( + string suffix, + XResourceDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Get Resources of Specified Resource ... + /// + /// + /// + /// + Task GetResource( + string suffix, + CancellationToken cancellationToken = default + ); + + /// + /// Remove Specified Suffix Resources ... + /// + /// + /// + /// + /// + Task Remove( + string suffix, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + /// + /// + Task Remove( + string resource, + string language, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} \ No newline at end of file diff --git a/Models/Dtos/XStringDto.cs b/Models/Dtos/XStringDto.cs index 65bbb1f..e8a7636 100644 --- a/Models/Dtos/XStringDto.cs +++ b/Models/Dtos/XStringDto.cs @@ -2,9 +2,8 @@ using xModels.Base; namespace xStringService.Models.Dtos { - public class XStringDto : XBaseDto + public class XStringDto : XBaseIntIDEntityDto { - public int Id { get; set; } public string Language { get; set; } public string ResourceTitle { get; set; } public string TranslatedValue { get; set; } diff --git a/Providers/Dtos/XStringDtoHub.cs b/Providers/Dtos/XStringDtoHub.cs new file mode 100644 index 0000000..ee0fc9d --- /dev/null +++ b/Providers/Dtos/XStringDtoHub.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Logging; +using xPushService.Base; +using xStringService.Interfaces.Dtos; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Dtos +{ + public class XStringDtoHub : XBaseDtoHub, IXStringDtoHub + { + public XStringDtoHub( + ILogger logger + ) : base(logger) + { } + } +} \ No newline at end of file diff --git a/Providers/Dtos/XStringRepositoryService.cs b/Providers/Dtos/XStringRepositoryService.cs new file mode 100644 index 0000000..4b38a69 --- /dev/null +++ b/Providers/Dtos/XStringRepositoryService.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using AutoMapper; +using xDataService.Providers; +using xStringService.Interfaces.Dtos; +using xStringService.Interfaces.Entities; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Dtos +{ + public class XStringRepositoryService : XBaseRepositoryService, IXStringRepositoryService + { + public XStringRepositoryService( + IXStringRepository repository, + IEnumerable mapperProfiles = null + ) : base( + repository, + mapperProfiles + ) + { } + } +} \ No newline at end of file diff --git a/Providers/Dtos/XStringServiceProvider.cs b/Providers/Dtos/XStringServiceProvider.cs new file mode 100644 index 0000000..d332fc8 --- /dev/null +++ b/Providers/Dtos/XStringServiceProvider.cs @@ -0,0 +1,1150 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using xCommons.Configurations; +using xCommons.Extensions; +using xDataService.Configuration; +using xExceptions.Constants; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Constants; +using xStringService.Extensions; +using xStringService.Interfaces.Dtos; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Dtos +{ + public class XStringServiceProvider : XBaseDtoProvider, IXStringServiceProvider + { + public XAppConfiguration AppConfiguration { get; } + + public XStringServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXStringRepositoryService service, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { + AppConfiguration = appConfiguration; + } + + // + #region Retrievers ... + /// + /// Retrieve all Exists Languages ... + /// + /// + /// + public async Task> GetLanguages( + CancellationToken cancellationToken = default + ) + { + // + var result = (await Service.GetAllAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.Language) + )) + .AsQueryable() + .Select(e => e.Language) + .Distinct() + .ToList(); + + // + // Check Configuration Default Language Exists ... + var hasDefaultLanguage = !AppConfiguration.DefaultLanguage.IsNullOrEmpty(); + if (hasDefaultLanguage) + { + // + // Find Default Language on Result ... + hasDefaultLanguage = result.Any(e => e.ToNormalString() == AppConfiguration.DefaultLanguage.ToNormalString()); + if (!hasDefaultLanguage) + { + result.Add(AppConfiguration.DefaultLanguage); + } + } + + // + result = result + .Distinct() + .ToList(); + + // + return result; + } + + /// + /// Check Specified Resource Exists or not ... + /// + /// + /// + /// + /// + public async Task IsResourceExists( + string resource, + string language = null, + CancellationToken cancellationToken = default + ) + { + // + var result = false; + + // + // Validate ... + result = !resource.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + XStringDto dto = null; + if (language.IsNullOrEmpty()) + { + // + dto = await Service + .FindOneAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: e => e.ResourceTitle == resource + ); + } + else + { + // + dto = await Service + .FindOneAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: + e => e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + } + + // + result = !dto.IsNullOrDefault(); + + // + return result; + } + + /// + /// Retrieve Specified Resource ... + /// + /// + /// + /// + /// + public async Task Get( + string resource, + string language = null, + CancellationToken cancellationToken = default + ) + { + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + if (resource.IsNullOrEmpty() || language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Resource Exists ... + var isExists = await IsResourceExists( + resource: resource, + language: language + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + var result = await Service + .FindOneAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Retrieve Specified Translation of Specified Resource ... + /// + /// + /// + /// + /// + public async Task GetResourceValue( + string resource, + string language = null, + CancellationToken cancellationToken = default + ) + { + // + var result = ""; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + var isValid = + !resource.IsNullOrEmpty() && + !language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Langauage Exists ... + var languages = await GetLanguages(cancellationToken); + isValid = languages.Any(l => l.ToNormalString() == language.ToNormalString()); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Check Resource Exists ... + isValid = await IsResourceExists( + resource: resource, + language: language, + cancellationToken: cancellationToken + ); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var dto = await Service.FindOneAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + isValid = !dto.IsNullOrDefault(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + + // + result = dto.TranslatedValue; + + // + return result; + } + + /// + /// Retrieve an Specified Resource Items ... + /// + /// + /// + /// + public async Task> GetResources( + string resource, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = await IsResourceExists(resource); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = await Service + .FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + predicate: e => + e.ResourceTitle == resource, + orderBuilder: x => + x.OrderBy(y => y.ResourceTitle), + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Specified Resource Items as XResourceDto Presentation ... + /// + /// + /// + /// + public async Task GetResource( + string resource, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isExists = await IsResourceExists( + language: null, + resource: resource, + cancellationToken: cancellationToken + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Retrieve String Dto (s) ... + var resources = await GetResources( + resource: resource, + cancellationToken: cancellationToken + ); + if (!resource.HasChild()) + { + XException.NotFound.Throw(); + } + + // + var result = new XResourceDto + { + Resource = resource, + Locales = resources.ToXLocaleResourceDtos() + }; + + // + return result; + } + #endregion + + // + #region Query ... + /// + /// Query Resource IDs ... + /// + /// + /// + /// + public async Task> QueryResourceIds( + XQuery query, + CancellationToken cancellationToken = default + ) + { + // + var dtoResult = await Service.QueryAsync( + query: query, + predicate: null, + includeBuilder: null, + ignoreSoftDeleteds: true, + orderBuilder: x => + x.OrderBy(y => y.ResourceTitle), + cancellationToken: cancellationToken + ); + + // + var result = new XQueryResult() + .UpdateData( + updateWith: dtoResult, + propertyBlackList: new List + { + nameof(XQueryResult.Items) + }); + + // + result.Items = dtoResult.Items.ToList().Select(dto => dto.ResourceTitle); + + // + return result; + } + + /// + /// Query Specified Language Resources ... + /// + /// + /// + /// + /// + public async Task> QueryLanguageResources( + XQuery query, + string language = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await Service.QueryAsync( + query: query, + includeBuilder: null, + ignoreSoftDeleteds: true, + orderBuilder: x => x + .OrderBy(y => y.Language) + .ThenBy(y => y.ResourceTitle), + cancellationToken: cancellationToken, + predicate: x => + x.Language.ToNormalString() == language.ToNormalString() + ); + + // + return result; + } + + /// + /// Query Locale Resources ... + /// + /// + /// + /// + /// + public async Task> QueryLocaleResources( + XQuery query, + string language = null, + CancellationToken cancellationToken = default + ) + { + // + Expression> predicate = null; + if (!language.IsNullOrEmpty()) + { + // + predicate = x => + x.Language.ToNormalString() == language.ToNormalString(); + } + + // + var dtoResult = await Service.QueryAsync( + query: query, + includeBuilder: null, + predicate: predicate, + ignoreSoftDeleteds: true, + orderBuilder: x => x + .OrderBy(y => y.Language) + .ThenBy(y => y.ResourceTitle), + cancellationToken: cancellationToken + ); + + // + var result = new XQueryResult() + .UpdateData( + updateWith: dtoResult, + propertyBlackList: new List + { + nameof(XQueryResult.Items) + }); + + // + result.Items = dtoResult.Items.ToList().ToXLocaleResourceDtos(); + + // + return result; + } + #endregion + + // + #region Add/Update Actions ... + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + /// + /// + public async Task Add( + string resource, + string value, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + bool result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + result = + !value.IsNullOrEmpty() && + !resource.IsNullOrEmpty() && + !language.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Exists ... + bool isExists = await IsResourceExists( + resource: resource, + language: language, + cancellationToken: cancellationToken + ); + result = !isExists; + if (!result) + { + XException.Duplicate.Throw(); + } + + // + // Prepare Entity to Add ... + XStringDto item = new XStringDto + { + Language = language, + TranslatedValue = value, + ResourceTitle = resource, + }; + item = await AddAsync( + item: item, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + result = !item.IsNullOrDefault(); + + // + return result; + } + + /// + /// Update Resource ... + /// + /// + /// + /// + /// + /// + /// + public async Task Update( + string resource, + string value, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + bool result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + result = + !value.IsNullOrEmpty() && + !language.IsNullOrEmpty() && + !resource.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Value Must Exists ... + result = await IsResourceExists( + resource: resource, + language: language, + cancellationToken: cancellationToken + ); + if (!result) + { + XException.NotFound.Throw(); + } + + // + var item = await Get( + language: language, + resource: resource, + cancellationToken: cancellationToken + ); + item.TranslatedValue = value; + item = await UpdateAsync( + item: item, + id: item.Id, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + result = !item.IsNullOrDefault(); + + // + return result; + } + + /// + /// Add Or Update Resource ... + /// + /// + /// + /// + /// + /// + /// + public async Task AddOrUpdate( + string resource, + string value, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + var result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Check Existsance ... + bool isExists = await IsResourceExists( + resource: resource, + language: language + ); + + // + // Act Based on Existance ... + if (isExists) + { + // + result = await Update( + value: value, + resource: resource, + language: language, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + result = await Add( + value: value, + resource: resource, + language: language, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// Add Specified Locale Resource ... + /// + /// + /// + /// + /// + /// + public async Task AddByLocaleResource( + XLocaleResourceDto item, + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + !resource.IsNullOrEmpty() && + !item.Value.IsNullOrEmpty() && + !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Specified Resource / Language Exists ... + isValid = await IsResourceExists( + resource: resource, + language: item.Language, + cancellationToken: cancellationToken + ); + if (isValid) + { + XException.Duplicate.Throw(); + } + + // + // Prepare Item to Add ... + var result = new XStringDto + { + Language = item.Language, + ResourceTitle = resource, + TranslatedValue = item.Value + }; + result = await AddAsync( + item: result, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Update Specified Locale Resource ... + /// + /// + /// + /// + /// + /// + public async Task UpdateByLocaleResource( + XLocaleResourceDto item, + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + !resource.IsNullOrEmpty() && + !item.Value.IsNullOrEmpty() && + !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Specified Resource / Language Exists ... + isValid = await IsResourceExists( + resource: resource, + language: item.Language, + cancellationToken: cancellationToken + ); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = await Get( + resource: resource, + language: item.Language, + cancellationToken: cancellationToken + ); + isValid = !result.IsNullOrDefault(); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Update ... + result.TranslatedValue = item.Value; + result = await UpdateAsync( + item: result, + id: result.Id, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + isValid = !result.IsNullOrDefault(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Add Or Update Resource By Locale ... + /// + /// + /// + /// + /// + /// + public async Task AddOrUpdateByLocaleResource( + XLocaleResourceDto item, + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + !resource.IsNullOrEmpty() && + !item.Value.IsNullOrEmpty() && + !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Specified Resource / Language Exists ... + isValid = await IsResourceExists( + resource: resource, + language: item.Language, + cancellationToken: cancellationToken + ); + + // + XStringDto result = null; + if (!isValid) + { + // + result = await AddByLocaleResource( + item: item, + resource: resource, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + result = await UpdateByLocaleResource( + item: item, + resource: resource, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Add Or Update all XResourceDto(s) Locales ... + /// + /// + /// + /// + /// + public async Task> AddByResource( + XResourceDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + item.Locales.HasChild() && + !item.Resource.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Task + .WhenAll(item.Locales + .Select(async e => await AddOrUpdateByLocaleResource( + item: e, + resource: item.Resource, + connectionId: connectionId, + cancellationToken: cancellationToken))); + + // + return result; + } + #endregion + + // + #region Remove Actions ... + /// + /// Remove all Specified Language's Resources ... + /// + /// + /// + /// + /// + public async Task RemoveLanguageResources( + string language, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = !language.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var dtos = await Service + .FindManyAsync( + orderBuilder: null, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: e => + e.Language.ToNormalString() == language.ToNormalString()); + + // + try + { + // + await Service.RemoveRangeAsync( + items: dtos, + softDelete: false, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + var ids = dtos.Select(e => e.Id); + await SendPush( + connectionId: connectionId, + payLoad: ids.ToJSON(camelCase: true), + cancellationToken: cancellationToken, + action: XBaseEntityHubAction.DeleteMany.GetStringValue() + ); + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// Remove all Specified Resource Ids instances ... + /// + /// + /// + /// + /// + public async Task> RemoveResource( + string resource, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = !resource.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Service + .FindManyAsync( + orderBuilder: null, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: e => + e.ResourceTitle.ToNormalString() == resource.ToNormalString()); + + // + try + { + // + await Service.RemoveRangeAsync( + items: result, + softDelete: false, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + var ids = result.Select(e => e.Id); + await SendPush( + connectionId: connectionId, + payLoad: ids.ToJSON(camelCase: true), + cancellationToken: cancellationToken, + action: XBaseEntityHubAction.DeleteMany.GetStringValue() + ); + } + catch (Exception ex) + { + throw ex; + } + + // + return result; + } + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + /// + /// + public async Task Remove( + string resource, + string language = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + bool result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + result = + !language.IsNullOrEmpty() && + !resource.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Resource Exists ... + result = await IsResourceExists( + language: language, + resource: resource, + cancellationToken: cancellationToken + ); + if (!result) + { + return result; + } + + // + var dto = await Get( + language: language, + resource: resource, + cancellationToken: cancellationToken + ); + result = !dto.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + dto = await RemoveAsync( + id: dto.Id, + softDelete: false, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + result = !dto.IsNullOrDefault(); + + // + return result; + } + + /// + /// Remove all Resource of Specified XResourceDto ... + /// + /// + /// + /// + /// + public async Task RemoveByResource( + XResourceDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + bool isValid = + !item.IsNullOrDefault() && + item.Locales.HasChild() && + !item.Resource.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + foreach (var locale in item.Locales) + { + // + await Remove( + resource: item.Resource, + language: locale.Language, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + } + #endregion + } +} \ No newline at end of file diff --git a/Providers/Entities/XStringEFRepository.cs b/Providers/Entities/XStringEFRepository.cs new file mode 100644 index 0000000..57b6f56 --- /dev/null +++ b/Providers/Entities/XStringEFRepository.cs @@ -0,0 +1,26 @@ +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringEFRepository : XBaseEFRepository + where TContext : XDbContext + { + protected XStringEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXStringKeyGenerator keyGenerator = null, + IXStringRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} \ No newline at end of file diff --git a/Providers/Entities/XStringEntityHub.cs b/Providers/Entities/XStringEntityHub.cs new file mode 100644 index 0000000..11d5378 --- /dev/null +++ b/Providers/Entities/XStringEntityHub.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.Logging; +using xPushService.Base; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringEntityHub : XBaseEntityHub, IXStringEntityHub + { + public XStringEntityHub( + ILogger logger + ) : base(logger) + { } + } +} \ No newline at end of file diff --git a/Providers/Entities/XStringEvents.cs b/Providers/Entities/XStringEvents.cs new file mode 100644 index 0000000..35b1aba --- /dev/null +++ b/Providers/Entities/XStringEvents.cs @@ -0,0 +1,9 @@ +using xDataService.Providers; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringRepositoryEvents : XBaseRepositoryEvents, IXStringRepositoryEvents + {} +} \ No newline at end of file diff --git a/Providers/Entities/XStringInMemoeryRepository.cs b/Providers/Entities/XStringInMemoeryRepository.cs new file mode 100644 index 0000000..cda6a7b --- /dev/null +++ b/Providers/Entities/XStringInMemoeryRepository.cs @@ -0,0 +1,21 @@ +using xDataService.Configuration; +using xDataService.Providers; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringInMemoeryRepository : XBaseInMemoryRepository, IXStringRepository + { + public XStringInMemoeryRepository( + XDataServiceConfiguration configuration, + IXStringKeyGenerator keyGenerator = null, + IXStringRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} \ No newline at end of file diff --git a/Providers/Entities/XStringKeyGenerator.cs b/Providers/Entities/XStringKeyGenerator.cs new file mode 100644 index 0000000..64a8e70 --- /dev/null +++ b/Providers/Entities/XStringKeyGenerator.cs @@ -0,0 +1,9 @@ +using xDataService.Providers; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringKeyGenerator : XIntKeyGenerator, IXStringKeyGenerator + { } +} \ No newline at end of file diff --git a/Providers/Entities/XStringMongoRepository.cs b/Providers/Entities/XStringMongoRepository.cs new file mode 100644 index 0000000..7cb122e --- /dev/null +++ b/Providers/Entities/XStringMongoRepository.cs @@ -0,0 +1,25 @@ +using xDataService.Configuration; +using xDataService.Providers; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringMongoRepository : XBaseMongoRepository, IXStringRepository + { + public XStringMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXStringKeyGenerator keyGenerator = null, + IXStringRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} \ No newline at end of file diff --git a/Providers/Entities/XStringRepositoryProvider.cs b/Providers/Entities/XStringRepositoryProvider.cs new file mode 100644 index 0000000..2ac5c58 --- /dev/null +++ b/Providers/Entities/XStringRepositoryProvider.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.SignalR; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.Providers.Entities +{ + public class XStringRepositoryProvider : XBaseEntityProvider, IXStringRepositoryProvider + { + public XStringRepositoryProvider( + IHubContext hub, + IXStringRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} \ No newline at end of file diff --git a/DataHelper/GraphQL/XStringGraphQLTypeHelper.cs b/Providers/GraphQL/XStringGraphQLTypeHelper.cs similarity index 93% rename from DataHelper/GraphQL/XStringGraphQLTypeHelper.cs rename to Providers/GraphQL/XStringGraphQLTypeHelper.cs index 3ede619..bb1e819 100644 --- a/DataHelper/GraphQL/XStringGraphQLTypeHelper.cs +++ b/Providers/GraphQL/XStringGraphQLTypeHelper.cs @@ -3,7 +3,7 @@ using xDataService.GraphQL; using xStringService.Interfaces.Entities; using xStringService.Models.Entities; -namespace xStringService.DataHelper.GraphQL +namespace xStringService.Providers.GraphQL { public class XStringGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXStringGraphQLTypeHelper { diff --git a/DataHelper/GraphQL/XStringGraphQuery.cs b/Providers/GraphQL/XStringGraphQuery.cs similarity index 93% rename from DataHelper/GraphQL/XStringGraphQuery.cs rename to Providers/GraphQL/XStringGraphQuery.cs index fb6a1ba..03c15cd 100644 --- a/DataHelper/GraphQL/XStringGraphQuery.cs +++ b/Providers/GraphQL/XStringGraphQuery.cs @@ -4,7 +4,7 @@ using xDataService.GraphQL; using xStringService.Interfaces.Entities; using xStringService.Models.Entities; -namespace xDataHelper.GraphQL +namespace xDataHelper.Providers.GraphQL { public class XStringGraphQuery : XBaseGraphQLQuery { diff --git a/DataHelper/GraphQL/XStringGraphSchema.cs b/Providers/GraphQL/XStringGraphSchema.cs similarity index 87% rename from DataHelper/GraphQL/XStringGraphSchema.cs rename to Providers/GraphQL/XStringGraphSchema.cs index f28d89e..08ebb10 100644 --- a/DataHelper/GraphQL/XStringGraphSchema.cs +++ b/Providers/GraphQL/XStringGraphSchema.cs @@ -1,7 +1,7 @@ using System; using GraphQL.Types; -namespace xDataHelper.GraphQL +namespace xDataHelper.Providers.GraphQL { public class XStringGraphSchema : Schema { diff --git a/DataHelper/GraphQL/XStringGraphType.cs b/Providers/GraphQL/XStringGraphType.cs similarity index 89% rename from DataHelper/GraphQL/XStringGraphType.cs rename to Providers/GraphQL/XStringGraphType.cs index 54e9bbc..93facfc 100644 --- a/DataHelper/GraphQL/XStringGraphType.cs +++ b/Providers/GraphQL/XStringGraphType.cs @@ -1,7 +1,7 @@ using xDataService.GraphQL; using xStringService.Models.Entities; -namespace xDataHelper.GraphQL +namespace xDataHelper.Providers.GraphQL { public class XStringGraphType : XBaseGraphObjectType { diff --git a/Providers/XBaseStringResourceProvider.cs b/Providers/XBaseStringResourceProvider.cs new file mode 100644 index 0000000..a0cdba3 --- /dev/null +++ b/Providers/XBaseStringResourceProvider.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using xCommons.Configurations; +using xCommons.Extensions; +using xExceptions.Constants; +using xModels.Dtos; +using xStringService.Extensions; +using xStringService.Interfaces; +using xStringService.Interfaces.Dtos; +using xStringService.Models.Dtos; + +namespace xStringService.Providers +{ + /// + /// a Base Class for Handling Resources Based on Specified Types on + /// String Resources Use ... + /// such as: + /// - Terms and Conditions; + /// - Contents; + /// - News; + /// - etc ... + /// + public abstract class XBaseStringResourceProvider : IXBaseStringResourceProvider + { + // + #region Props ... + public string Prefix { get; } + public IXStringServiceProvider Provider { get; } + public XAppConfiguration AppConfiguration { get; } + #endregion + + // + #region Constructor ... + public XBaseStringResourceProvider( + string prefix, + IXStringServiceProvider provider, + XAppConfiguration appConfiguration + ) + { + // + Prefix = prefix; + Provider = provider; + AppConfiguration = appConfiguration; + } + #endregion + + // + #region Actions ... + /// + /// Prepare Resource Title by Given Data ... + /// + /// + /// + public string GetResourceTitle(string suffix) + { + // + string result = ""; + + // + if (suffix.IsNullOrEmpty()) + { + return result; + } + + // + result = $"{Prefix}_${suffix}"; + + // + return result; + } + + /// + /// Add Specified Locales ... + /// + /// + /// + /// + /// + /// + public async Task> Add( + string suffix, + IEnumerable locales, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var has = + locales.HasChild() && + !suffix.IsNullOrEmpty(); + if (!has) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Resource ID ... + string resourceID = GetResourceTitle(suffix); + var result = await locales.SelectAsync(async l => + { + // + // Normalize Language ... + if (l.Language.IsNullOrEmpty()) + { + l.Language = AppConfiguration.DefaultLanguage; + } + + // + // Prepare Model for Add ... + var model = new XStringDto + { + Language = l.Language, + TranslatedValue = l.Value, + ResourceTitle = resourceID, + }; + model = await Provider.AddAsync( + item: model, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + return model; + }); + + // + return result; + } + + /// + /// Add Or Update Specified Locals ... + /// + /// + /// + /// + /// + /// + public async Task> AddOrUpdate( + string resource, + IEnumerable locales, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = + locales.HasChild() && + !resource.IsNullOrEmpty() && + locales.All(l => !l.Value.IsNullOrEmpty() && !l.Language.IsNullOrEmpty()); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Resource ... + isValid = resource.Contains(Prefix); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + var result = await locales.SelectAsync(async l => + await Provider.AddOrUpdateByLocaleResource( + item: l, + resource: resource, + connectionId: connectionId, + cancellationToken: cancellationToken + ) + ); + + // + return result; + } + + /// + /// Get Specified Locale ... + /// + /// + /// + /// + /// + public async Task GetLocale( + string suffix, + string language = null, + CancellationToken cancellationToken = default + ) + { + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + if (suffix.IsNullOrEmpty() || language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Resource Title ... + string resource = GetResourceTitle(suffix); + + // + // Check Resource Exists ... + var isExists = await Provider.IsResourceExists( + resource: resource, + language: language, + cancellationToken: cancellationToken + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Retrieve and Validate Dto Model ... + var model = await Provider.Get( + resource: resource, + language: language, + cancellationToken: cancellationToken + ); + if (model.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + // Prepare Result ... + var result = model + .ToXLocaleResourceDto(); + return result; + } + + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + /// + public async Task AddResource( + string suffix, + XResourceDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + if (suffix.IsNullOrEmpty() || + item.IsNull() || + !item.Locales.HasChild() || + !item.Locales.All(l => !l.Value.IsNullOrEmpty())) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Resource ID ... + var addedLocals = await Add( + suffix: suffix, + locales: item.Locales, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!addedLocals.HasChild()) + { + XException.ActionFailed.Throw(); + } + + // + var result = await GetResource( + suffix: suffix, + cancellationToken: cancellationToken + ); + return result; + } + + /// + /// Get Resources of Specified Resource ... + /// + /// + /// + /// + public async Task GetResource( + string suffix, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + if (suffix.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Resource ID ... + string resourceID = GetResourceTitle(suffix); + + // + // Prepare ... + var result = await Provider.GetResource( + resource: resourceID, + cancellationToken: cancellationToken + ); + return result; + } + + /// + /// Remove Specified Suffix Resources ... + /// + /// + /// + /// + /// + public async Task Remove( + string suffix, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + if (suffix.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + var resourceID = GetResourceTitle(suffix); + await Provider.RemoveResource( + resource: resourceID, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + /// + /// + public async Task Remove( + string resource, + string language, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + bool isValid = + !resource.IsNullOrEmpty() && + !language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check resource ID Contains Prefix ... + isValid = resource.Contains(Prefix); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + // Check Exists ... + var isExists = await Provider.IsResourceExists( + resource: resource, + language: language, + cancellationToken: cancellationToken + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Remove Resource ... + await Provider.Remove( + resource: resource, + language: language, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + #endregion + } +} \ No newline at end of file