From 9b3cec02c2f3d4e754ce64674d714074a809e48a Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 16 Nov 2025 15:58:48 +0330 Subject: [PATCH] last ... --- Constants/XStringHubAction.cs | 10 + .../XStringServiceControllerBase.cs | 104 +++++-- Hubs/XStringHub.cs | 15 + Interfaces/IXStringProvider.cs | 77 +++-- .../IXStringServiceControllerActions.cs | 2 +- Providers/XStringProvider.cs | 269 ++++++++++++++++-- xStringService.csproj | 9 +- 7 files changed, 427 insertions(+), 59 deletions(-) create mode 100644 Constants/XStringHubAction.cs rename {Controller => Controllers}/XStringServiceControllerBase.cs (88%) create mode 100644 Hubs/XStringHub.cs diff --git a/Constants/XStringHubAction.cs b/Constants/XStringHubAction.cs new file mode 100644 index 0000000..2cf4c3e --- /dev/null +++ b/Constants/XStringHubAction.cs @@ -0,0 +1,10 @@ +using xExceptions.Attributes; + +namespace xStringService.Constants +{ + public enum XStringHubAction + { + [StringValue("ItemsDeleted")] + ItemsDeleted + } +} \ No newline at end of file diff --git a/Controller/XStringServiceControllerBase.cs b/Controllers/XStringServiceControllerBase.cs similarity index 88% rename from Controller/XStringServiceControllerBase.cs rename to Controllers/XStringServiceControllerBase.cs index e96e661..7d88a31 100644 --- a/Controller/XStringServiceControllerBase.cs +++ b/Controllers/XStringServiceControllerBase.cs @@ -12,7 +12,7 @@ using xModels.Dtos; using xStringService.Interfaces; using xStringService.Models.Dtos; -namespace xStringService.Controllerppa +namespace xStringService.Controllers { public abstract class XStringServiceControllerBase : XIBaseProviderController, IXStringServiceControllerActions { @@ -243,7 +243,7 @@ namespace xStringService.Controllerppa /// /// [HttpGet("QueryResourceIds")] - public virtual async Task>> QueryResourceIds( + public virtual ActionResult> QueryResourceIds( [FromQuery] XQuery query ) { @@ -252,7 +252,7 @@ namespace xStringService.Controllerppa try { // - var result = await StringProvider + var result = StringProvider .QueryResourceIds(query); // @@ -358,12 +358,16 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .Add( value: value, resource: resource, - language: language + language: language, + connectionId: connectionId ); // @@ -396,12 +400,16 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .Update( value: value, resource: resource, - language: language + language: language, + connectionId: connectionId ); // @@ -434,12 +442,16 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .AddOrUpdate( value: value, resource: resource, - language: language + language: language, + connectionId: connectionId ); // @@ -469,7 +481,13 @@ namespace xStringService.Controllerppa try { // - var result = await StringProvider.AddEntity(item); + var connectionId = GetConnectionId(); + + // + var result = await StringProvider.AddEntity( + item: item, + connectionId: connectionId + ); // return Ok(result. @@ -497,9 +515,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider - .UpdateEntity(item); + .UpdateEntity( + item: item, + connectionId: connectionId + ); // return Ok(result. @@ -527,9 +551,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider - .AddOrUpdateEntity(item); + .AddOrUpdateEntity( + item: item, + connectionId: connectionId + ); // return Ok(result. @@ -559,11 +589,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .AddByLocaleResource( item: item, - resource: resource + resource: resource, + connectionId: connectionId ); // @@ -594,11 +628,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .UpdateByLocaleResource( item: item, - resource: resource + resource: resource, + connectionId: connectionId ); // @@ -629,11 +667,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .AddOrUpdateByLocaleResource( item: item, - resource: resource + resource: resource, + connectionId: connectionId ); // @@ -662,9 +704,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider - .AddByResource(item); + .AddByResource( + item: item, + connectionId: connectionId + ); // return Ok(result. @@ -695,9 +743,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // await StringProvider - .RemoveLanguageResources(language); + .RemoveLanguageResources( + language: language, + connectionId: connectionId + ); // return Ok(); @@ -724,9 +778,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider - .RemoveResource(resource); + .RemoveResource( + resource: resource, + connectionId: connectionId + ); // return Ok(result. @@ -756,11 +816,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // var result = await StringProvider .Remove( resource: resource, - language: language + language: language, + connectionId: connectionId ); // @@ -789,9 +853,15 @@ namespace xStringService.Controllerppa // Do ... try { + // + var connectionId = GetConnectionId(); + // await StringProvider - .RemoveByResource(item); + .RemoveByResource( + item: item, + connectionId: connectionId + ); // return Ok(); diff --git a/Hubs/XStringHub.cs b/Hubs/XStringHub.cs new file mode 100644 index 0000000..78076c9 --- /dev/null +++ b/Hubs/XStringHub.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.Logging; +using xPushService.Base; +using xStringService.Models.Entities; + +namespace xStringService.Hubs +{ + public class XStringHub : XBaseEntityHub + { + // + #region Constructor ... + public XStringHub(ILogger logger) : base(logger) + { } + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/IXStringProvider.cs b/Interfaces/IXStringProvider.cs index 2d3b82e..6e9c08f 100644 --- a/Interfaces/IXStringProvider.cs +++ b/Interfaces/IXStringProvider.cs @@ -2,9 +2,11 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; using xCommons.Configurations; using xDataService.Configuration; using xModels.Dtos; +using xStringService.Hubs; using xStringService.Interfaces.Entities; using xStringService.Models.Dtos; using xStringService.Models.Entities; @@ -15,6 +17,7 @@ namespace xStringService.Interfaces { // #region Props ... + IHubContext Hub { get; } IXStringRepository Repository { get; } XAppConfiguration AppConfiguration { get; } XDataServiceConfiguration DataConfiguration { get; } @@ -38,7 +41,7 @@ namespace xStringService.Interfaces string resource, string language = null ); - + /// /// Retrieve Specified Resource ... /// @@ -83,7 +86,7 @@ namespace xStringService.Interfaces /// /// /// - Task> QueryResourceIds(XQuery query); + XQueryResult QueryResourceIds(XQuery query); /// /// Query Specified Language Resources ... @@ -129,11 +132,13 @@ namespace xStringService.Interfaces /// /// /// + /// /// Task Add( string resource, string value, - string language = null + string language = null, + string connectionId = null ); /// @@ -142,11 +147,13 @@ namespace xStringService.Interfaces /// /// /// + /// /// Task Update( string resource, string value, - string language = null + string language = null, + string connectionId = null ); /// @@ -155,43 +162,59 @@ namespace xStringService.Interfaces /// /// /// + /// /// Task AddOrUpdate( string resource, string value, - string language = null + string language = null, + string connectionId = null ); /// /// Add Specified Resource ... /// /// + /// /// - Task AddEntity(XStringDto item); + Task AddEntity( + XStringDto item, + string connectionId = null + ); /// /// Update Specified Entity ... /// /// + /// /// - Task UpdateEntity(XStringDto item); + Task UpdateEntity( + XStringDto item, + string connectionId = null + ); /// /// Add Or Update Specified Entitiy ... /// /// + /// /// - Task AddOrUpdateEntity(XStringDto item); + Task AddOrUpdateEntity( + XStringDto item, + string connectionId = null + ); /// /// Add Specified Locale Resource ... /// /// /// + /// /// Task AddByLocaleResource( XLocaleResourceDto item, - string resource + string resource, + string connectionId = null ); /// @@ -199,10 +222,12 @@ namespace xStringService.Interfaces /// /// /// + /// /// Task UpdateByLocaleResource( XLocaleResourceDto item, - string resource + string resource, + string connectionId = null ); /// @@ -210,18 +235,24 @@ namespace xStringService.Interfaces /// /// /// + /// /// Task AddOrUpdateByLocaleResource( XLocaleResourceDto item, - string resource + string resource, + string connectionId = null ); /// /// Add Or Update all XResourceDto(s) Locales ... /// /// + /// /// - Task> AddByResource(XResourceDto item); + Task> AddByResource( + XResourceDto item, + string connectionId = null + ); #endregion // @@ -230,33 +261,47 @@ namespace xStringService.Interfaces /// Remove all Specified Language's Resources ... /// /// + /// /// - Task RemoveLanguageResources(string language); + Task RemoveLanguageResources( + string language, + string connectionId = null + ); /// /// Remove all Specified Resource Ids instances ... /// /// + /// /// - Task> RemoveResource(string resource); + Task> RemoveResource( + string resource, + string connectionId = null + ); /// /// Remove Specified Resource ... /// /// /// + /// /// Task Remove( string resource, - string language = null + string language = null, + string connectionId = null ); /// /// Remove all Resource of Specified XResourceDto ... /// /// + /// /// - Task RemoveByResource(XResourceDto item); + Task RemoveByResource( + XResourceDto item, + string connectionId = null + ); #endregion } } \ No newline at end of file diff --git a/Interfaces/IXStringServiceControllerActions.cs b/Interfaces/IXStringServiceControllerActions.cs index 522e3b7..d5d8d23 100644 --- a/Interfaces/IXStringServiceControllerActions.cs +++ b/Interfaces/IXStringServiceControllerActions.cs @@ -75,7 +75,7 @@ namespace xStringService.Interfaces /// /// /// - Task>> QueryResourceIds( + ActionResult> QueryResourceIds( [FromQuery] XQuery query ); diff --git a/Providers/XStringProvider.cs b/Providers/XStringProvider.cs index 05e192a..04d9c31 100644 --- a/Providers/XStringProvider.cs +++ b/Providers/XStringProvider.cs @@ -3,13 +3,18 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; +using DnsClient.Protocol; +using Microsoft.AspNetCore.SignalR; using xCommons.Configurations; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Extensions; using xExceptions.Constants; using xModels.Dtos; +using xPushService.Constants; +using xStringService.Constants; using xStringService.Extensions; +using xStringService.Hubs; using xStringService.Interfaces; using xStringService.Interfaces.Entities; using xStringService.Models.Dtos; @@ -21,6 +26,7 @@ namespace xStringService.Providers { // #region Props ... + public IHubContext Hub { get; } public IXStringRepository Repository { get; } public XAppConfiguration AppConfiguration { get; } public XDataServiceConfiguration DataConfiguration { get; } @@ -31,13 +37,15 @@ namespace xStringService.Providers public XStringProvider( IXStringRepository repository, XAppConfiguration appConfiguration, - XDataServiceConfiguration dataConfiguration + XDataServiceConfiguration dataConfiguration, + IHubContext hub = null ) { // Repository = repository; AppConfiguration = appConfiguration; DataConfiguration = dataConfiguration; + Hub = hub; } #endregion @@ -304,7 +312,7 @@ namespace xStringService.Providers /// /// /// - public async Task> QueryResourceIds(XQuery query) + public XQueryResult QueryResourceIds(XQuery query) { // // Normalize ... @@ -410,7 +418,7 @@ namespace xStringService.Providers TotalPages = entityResult.TotalPages, TotalItems = entityResult.TotalItems, TotalFilteredPages = entityResult.TotalFilteredPages, - TotalFilteredItems = entityResult.TotalFilteredItems, + TotalFilteredItems = entityResult.TotalFilteredItems, Items = entityResult.Items.Select(i => i.ToXStringDto()), }; @@ -562,11 +570,13 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task Add( string resource, string value, - string language = null + string language = null, + string connectionId = null ) { // @@ -607,8 +617,17 @@ namespace xStringService.Providers TranslatedValue = value, ResourceTitle = resource, }; - var added = await Repository.AddAsync(entity); - result = !added.IsNullOrDefault(); + entity = await Repository.AddAsync(entity); + result = !entity.IsNullOrDefault(); + if (result) + { + // + await SendPush( + action: XBaseEntityHubAction.Add.GetStringValue(), + entityId: entity.Id, + connectionId: connectionId + ); + } // return result; @@ -620,11 +639,13 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task Update( string resource, string value, - string language = null + string language = null, + string connectionId = null ) { // @@ -674,6 +695,15 @@ namespace xStringService.Providers entity.TranslatedValue = value; entity = await Repository.UpdateAsync(entity.Id, entity); result = !entity.IsNullOrDefault(); + if (result) + { + // + await SendPush( + action: XBaseEntityHubAction.Update.GetStringValue(), + entityId: entity.Id, + connectionId: connectionId + ); + } // return result; @@ -685,11 +715,13 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task AddOrUpdate( string resource, string value, - string language = null + string language = null, + string connectionId = null ) { // @@ -738,8 +770,12 @@ namespace xStringService.Providers /// Add Specified Resource ... /// /// + /// /// - public async Task AddEntity(XStringDto item) + public async Task AddEntity( + XStringDto item, + string connectionId = null + ) { // // Validate ... @@ -787,6 +823,13 @@ namespace xStringService.Providers XException.ActionFailed.Throw(); } + // + await SendPush( + action: XBaseEntityHubAction.Add.GetStringValue(), + entityId: result.Id, + connectionId: connectionId + ); + // return result.ToXStringDto(); } @@ -795,8 +838,12 @@ namespace xStringService.Providers /// Update Specified Entity ... /// /// + /// /// - public async Task UpdateEntity(XStringDto item) + public async Task UpdateEntity( + XStringDto item, + string connectionId = null + ) { // // Validate ... @@ -852,6 +899,11 @@ namespace xStringService.Providers // XStringDto result = entity.ToXStringDto(); + await SendPush( + action: XBaseEntityHubAction.Update.GetStringValue(), + entityId: entity.Id, + connectionId: connectionId + ); // return result; @@ -861,8 +913,12 @@ namespace xStringService.Providers /// Add Or Update Specified Entitiy ... /// /// + /// /// - public async Task AddOrUpdateEntity(XStringDto item) + public async Task AddOrUpdateEntity( + XStringDto item, + string connectionId = null + ) { // // Validate ... @@ -897,11 +953,11 @@ namespace xStringService.Providers XStringDto result = null; if (!isExists) { - result = await AddEntity(item); + result = await AddEntity(item, connectionId); } else { - result = await UpdateEntity(item); + result = await UpdateEntity(item, connectionId); } if (result.IsNullOrDefault()) { @@ -917,10 +973,12 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task AddByLocaleResource( XLocaleResourceDto item, - string resource + string resource, + string connectionId = null ) { // @@ -954,7 +1012,7 @@ namespace xStringService.Providers ResourceTitle = resource, TranslatedValue = item.Value }; - result = await AddEntity(result); + result = await AddEntity(result, connectionId); // return result; @@ -965,10 +1023,12 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task UpdateByLocaleResource( XLocaleResourceDto item, - string resource + string resource, + string connectionId = null ) { // @@ -1015,6 +1075,13 @@ namespace xStringService.Providers // XStringDto result = entity.ToXStringDto(); + await SendPush( + action: XBaseEntityHubAction.Update.GetStringValue(), + entityId: entity.Id, + connectionId: connectionId + ); + + // return result; } @@ -1023,10 +1090,12 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task AddOrUpdateByLocaleResource( XLocaleResourceDto item, - string resource + string resource, + string connectionId = null ) { // @@ -1079,8 +1148,12 @@ namespace xStringService.Providers /// Add Or Update all XResourceDto(s) Locales ... /// /// + /// /// - public async Task> AddByResource(XResourceDto item) + public async Task> AddByResource( + XResourceDto item, + string connectionId = null + ) { // // Validate ... @@ -1109,8 +1182,12 @@ namespace xStringService.Providers /// Remove all Specified Language's Resources ... /// /// + /// /// - public async Task RemoveLanguageResources(string language) + public async Task RemoveLanguageResources( + string language, + string connectionId = null + ) { // // Validate ... @@ -1123,15 +1200,37 @@ namespace xStringService.Providers // var entities = await Repository .FindManyAsync(e => e.Language.ToNormalString() == language.ToNormalString()); - await Repository.RemoveRangeAsync(entities); + + // + try + { + // + await Repository.RemoveRangeAsync(entities); + + // + var entitieIds = entities.Select(e => e.Id); + await SendCustomPush( + action: XStringHubAction.ItemsDeleted.GetStringValue(), + payLoad: entitieIds.ToJSON(), + connectionId: connectionId + ); + } + catch (Exception ex) + { + throw ex; + } } /// /// Remove all Specified Resource Ids instances ... /// /// + /// /// - public async Task> RemoveResource(string resource) + public async Task> RemoveResource( + string resource, + string connectionId = null + ) { // // Validate ... @@ -1153,6 +1252,18 @@ namespace xStringService.Providers } } + // + if (result.HasChild()) + { + // + var ids = result.Select(i => i.Id); + await SendCustomPush( + action: XStringHubAction.ItemsDeleted.GetStringValue(), + payLoad: ids.ToJSON(), + connectionId: connectionId + ); + } + // return result; } @@ -1162,10 +1273,12 @@ namespace xStringService.Providers /// /// /// + /// /// public async Task Remove( string resource, - string language = null + string language = null, + string connectionId = null ) { // @@ -1215,6 +1328,15 @@ namespace xStringService.Providers // Delete ... entity = await Repository.RemoveAsync(entity.Id); result = !entity.IsNullOrDefault(); + if (result) + { + // + await SendPush( + action: XBaseEntityHubAction.Delete.GetStringValue(), + entityId: entity.Id, + connectionId: connectionId + ); + } // return result; @@ -1224,8 +1346,12 @@ namespace xStringService.Providers /// Remove all Resource of Specified XResourceDto ... /// /// + /// /// - public async Task RemoveByResource(XResourceDto item) + public async Task RemoveByResource( + XResourceDto item, + string connectionId = null + ) { // bool isValid = @@ -1237,7 +1363,7 @@ namespace xStringService.Providers XException.InvalidArgs.Throw(); } - // + // foreach (var locale in item.Locales) { // @@ -1248,5 +1374,100 @@ namespace xStringService.Providers } } #endregion + + // + #region Hub Actions ... + /// + /// Send Specified Hub Action Notifications ... + /// + /// + /// + /// + public async Task SendPush( + string action, + int entityId, + string connectionId = null + ) + { + // + var hubActions = new List + { + XBaseEntityHubAction.Add.GetStringValue(), + XBaseEntityHubAction.Delete.GetStringValue(), + XBaseEntityHubAction.Update.GetStringValue(), + }; + + // + // Validate ... + var isValid = + entityId > 0 && + !Hub.IsNull() && + !action.IsNullOrEmpty() && + hubActions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve and Validate Entity ... + XString entity = null; + try + { + entity = await Repository.GetAsync(entityId); + } + catch { } + isValid = !entity.IsNullOrDefault(); + if (!isValid) + { + return; + } + + // + var clients = Hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = Hub.Clients.AllExcept(connectionId); + } + await clients.SendAsync(action, entity, connectionId); + } + + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + public async Task SendCustomPush( + string action, + string payLoad, + string connectionId = null + ) + { + // + var customActions = new List + { + XStringHubAction.ItemsDeleted.GetStringValue(), + }; + + // + // Validate ... + var isValid = !action.IsNullOrEmpty() && + customActions.Contains(action); + if (!isValid) + { + return; + } + + // + var clients = Hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = Hub.Clients.AllExcept(connectionId); + } + await clients.SendAsync(action, payLoad, connectionId); + } + #endregion } } \ No newline at end of file diff --git a/xStringService.csproj b/xStringService.csproj index 5e3d087..ed0f07f 100644 --- a/xStringService.csproj +++ b/xStringService.csproj @@ -20,9 +20,16 @@ + + + + + + + - +