From 0ba543136d307df38b15f9fdc6a1533e69aeb79e Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Wed, 5 Nov 2025 05:09:38 +0330 Subject: [PATCH] Add XBaseResourceProvider Class and Interfaces for Handle String Resource Based Services Implementation ... --- Base/XBaseStringResourceProvider.cs | 349 +++++++++++++++++++++ DI/XDIHelperExtension.cs | 13 + Interfaces/IXBaseStringResourceProvider.cs | 98 ++++++ Interfaces/IXStringProvider.cs | 11 + Providers/XStringProvider.cs | 67 +++- 5 files changed, 530 insertions(+), 8 deletions(-) create mode 100644 Base/XBaseStringResourceProvider.cs create mode 100644 Interfaces/IXBaseStringResourceProvider.cs diff --git a/Base/XBaseStringResourceProvider.cs b/Base/XBaseStringResourceProvider.cs new file mode 100644 index 0000000..6971600 --- /dev/null +++ b/Base/XBaseStringResourceProvider.cs @@ -0,0 +1,349 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Threading.Tasks; +using xCommons.Configurations; +using xCommons.Extensions; +using xExceptions.Constants; +using xModels.Dtos; +using xStringService.Extensions; +using xStringService.Interfaces; +using xStringService.Models.Dtos; + +namespace xStringService.Base +{ + /// + /// 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 IXStringProvider Provider { get; } + public XAppConfiguration AppConfiguration { get; } + #endregion + + // + #region Constructor ... + public XBaseStringResourceProvider( + string prefix, + IXStringProvider 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 + ) + { + // + // 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.AddEntity(model); + return model; + }); + + // + return result; + } + + /// + /// Add Or Update Specified Locals ... + /// + /// + /// + /// + public async Task> AddOrUpdate( + string resource, + IEnumerable locales + ) + { + // + // 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 + ) + ); + + // + return result; + } + + /// + /// Get Specified Locale ... + /// + /// + /// + /// + public async Task GetLocale( + string suffix, + string language = null + ) + { + // + // 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 + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Retrieve and Validate Dto Model ... + var model = await Provider.Get( + resource: resource, + language: language + ); + 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 + ) + { + // + // 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, item.Locales); + if (!addedLocals.HasChild()) + { + XException.ActionFailed.Throw(); + } + + // + var result = await GetResource(suffix); + return result; + } + + /// + /// Get Resources of Specified Resource ... + /// + /// + /// + public async Task GetResource(string suffix) + { + // + // Validate ... + if (suffix.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Resource ID ... + string resourceID = GetResourceTitle(suffix); + + // + // Prepare ... + var result = await Provider.GetResource(resourceID); + return result; + } + + /// + /// Remove Specified Suffix Resources ... + /// + /// + /// + public async Task Remove(string suffix) + { + // + // Validate ... + if (suffix.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + var resourceID = GetResourceTitle(suffix); + await Provider.RemoveResource(resourceID); + } + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + public async Task Remove( + string resource, + string language + ) + { + // + // 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 + ); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Remove Resource ... + await Provider.Remove( + resource: resource, + language: language + ); + } + #endregion + } +} \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index 965c7f5..fcdf962 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -4,6 +4,7 @@ using xExceptions.Constants; using xCommons.Extensions; using xStringService.Interfaces; using xStringService.Providers; +using xStringService.Interfaces.Entities; namespace xStringService.DI { @@ -74,6 +75,18 @@ namespace xStringService.DI throw exception; } + // + // Check String Repository Exists ... + var isStringRepositoryExists = !services + .GetRegisteredService() + .IsNull(); + if (!isStringRepositoryExists) + { + // + Log("AddStringService failed, IXStringRepository not provided ..."); + throw exception; + } + // services.Add(new ServiceDescriptor(typeof(IXStringProvider), typeof(XStringProvider), lifeTime)); Log("AddStringService Succeed ..."); diff --git a/Interfaces/IXBaseStringResourceProvider.cs b/Interfaces/IXBaseStringResourceProvider.cs new file mode 100644 index 0000000..50217ad --- /dev/null +++ b/Interfaces/IXBaseStringResourceProvider.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using xCommons.Configurations; +using xModels.Dtos; +using xStringService.Models.Dtos; + +namespace xStringService.Interfaces +{ + public interface IXBaseStringResourceProvider + { + // + #region Props ... + string Prefix { get; } + IXStringProvider 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 + ); + + /// + /// Add Or Update Specified Locals ... + /// + /// + /// + /// + Task> AddOrUpdate( + string resource, + IEnumerable locales + ); + + /// + /// Get Specified Locale ... + /// + /// + /// + /// + Task GetLocale( + string suffix, + string language = null + ); + + /// + /// Add Specified Resource ... + /// + /// + /// + /// + Task AddResource( + string suffix, + XResourceDto item + ); + + /// + /// Get Resources of Specified Resource ... + /// + /// + /// + Task GetResource(string suffix); + + /// + /// Remove Specified Suffix Resources ... + /// + /// + /// + Task Remove(string suffix); + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + Task Remove( + string resource, + string language + ); + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/IXStringProvider.cs b/Interfaces/IXStringProvider.cs index 32d3cc8..2d3b82e 100644 --- a/Interfaces/IXStringProvider.cs +++ b/Interfaces/IXStringProvider.cs @@ -38,6 +38,17 @@ namespace xStringService.Interfaces string resource, string language = null ); + + /// + /// Retrieve Specified Resource ... + /// + /// + /// + /// + Task Get( + string resource, + string language = null + ); /// /// Retrieve Specified Translation of Specified Resource ... diff --git a/Providers/XStringProvider.cs b/Providers/XStringProvider.cs index 1cb5399..53866e8 100644 --- a/Providers/XStringProvider.cs +++ b/Providers/XStringProvider.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using System.Reactive.Concurrency; using System.Threading.Tasks; using xCommons.Configurations; using xCommons.Extensions; @@ -126,6 +125,58 @@ namespace xStringService.Providers return result; } + /// + /// Retrieve Specified Resource ... + /// + /// + /// + /// + public async Task Get( + string resource, + string language = null + ) + { + // + // 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 entity = await Repository + .FindOneAsync(e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + if (entity.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return entity + .ToDynamicObject(); + } + /// /// Retrieve Specified Translation of Specified Resource ... /// @@ -417,19 +468,19 @@ namespace xStringService.Providers if (totalItemsCount > 0 && filteredItemsCount > 0) { - // - // Apply Paging ... - items = items.ApplyPaging( - query.Page, - query.PageSize - ); - // // Apply Sorting ... items = items.ApplySorting( query.SortBy, query.IsAscending ); + + // + // Apply Paging ... + items = items.ApplyPaging( + query.Page, + query.PageSize + ); } //