using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; 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.Extensions; using xStringService.Hubs; using xStringService.Interfaces; using xStringService.Interfaces.Entities; using xStringService.Models.Dtos; using xStringService.Models.Entities; namespace xStringService.Providers { public class XStringProvider : IXStringProvider { // #region Props ... public IHubContext Hub { get; } public IXStringRepository Repository { get; } public XAppConfiguration AppConfiguration { get; } public XDataServiceConfiguration DataConfiguration { get; } #endregion // #region Constructor ... public XStringProvider( IXStringRepository repository, XAppConfiguration appConfiguration, XDataServiceConfiguration dataConfiguration, IHubContext hub = null ) { // Repository = repository; AppConfiguration = appConfiguration; DataConfiguration = dataConfiguration; Hub = hub; } #endregion // #region Retrievers ... /// /// Retrieve all Exists Languages ... /// /// public async Task> GetLanguages() { // var result = (await Repository.GetAllAsync()) .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 ) { // var result = false; // // Validate ... result = !resource.IsNullOrEmpty(); if (!result) { return result; } // XString entity = null; if (language.IsNullOrEmpty()) { // entity = await Repository .FindOneAsync(e => e.ResourceTitle == resource); } else { // entity = await Repository .FindOneAsync(e => e.ResourceTitle == resource && e.Language.ToNormalString() == language.ToNormalString() ); } result = !entity.IsNullOrDefault(); // 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.ToXStringDto(); } /// /// Retrieve Specified Translation of Specified Resource ... /// /// /// /// public async Task GetResourceValue( string resource, string language = null ) { // 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(); isValid = languages.Any(l => l.ToNormalString() == language.ToNormalString()); if (!isValid) { XException.NotFound.Throw(); } // // Check Resource Exists ... isValid = await IsResourceExists(resource); if (!isValid) { XException.NotFound.Throw(); } // var entity = await Repository.FindOneAsync(e => e.ResourceTitle == resource && e.Language.ToNormalString() == language.ToNormalString() ); isValid = !entity.IsNullOrDefault(); if (!isValid) { XException.ActionFailed.Throw(); } // result = entity.TranslatedValue; // return result; } /// /// Retrieve an Specified Resource Items ... /// /// /// public async Task> GetResources(string resource) { // // Validate ... var isValid = await IsResourceExists(resource); if (!isValid) { XException.NotFound.Throw(); } // var result = (await Repository .FindManyAsync(e => e.ResourceTitle == resource)) .ToXStringDtos(); // return result; } /// /// Retrieve Specified Resource Items as XResourceDto Presentation ... /// /// /// public async Task GetResource(string resource) { // // Validate ... bool isExists = await IsResourceExists(resource); if (!isExists) { XException.NotFound.Throw(); } // // Retrieve String Dto (s) ... var resources = await GetResources(resource); if (!resource.HasChild()) { XException.NotFound.Throw(); } // var result = new XResourceDto { Resource = resource, Locales = resources.ToXLocaleResourceDtos() }; return result; } #endregion // #region Query ... /// /// Query Resource IDs ... /// /// /// public XQueryResult QueryResourceIds(XQuery query) { // // Normalize ... query = query.NormalizeQuery(DataConfiguration); // // Read Resource IDs ... var items = Repository .AsQueryable() .Select(e => e.ResourceTitle) .Distinct(); // var totalItemsCount = items.Count(); // // Apply Filter ... if (totalItemsCount > 0 && !query.Filter.IsNullOrEmpty()) { // items = items .Where(e => e.ToNormalString().Contains(query.Filter.ToNormalString())); } // var filteredItemsCount = items.Count(); var totalPagesCount = query.CountPages(totalItemsCount); var filteredPagesCount = query.CountPages(filteredItemsCount); // // Apply Paging / Sorting ... if (totalItemsCount > 0 && filteredItemsCount > 0) { // items = items.ApplyPaging( query.Page, query.PageSize ); } // // Prepare result ... var result = new XQueryResult { Items = items, Page = query.Page, PageSize = query.PageSize, TotalPages = totalPagesCount, TotalItems = totalItemsCount, TotalFilteredPages = filteredPagesCount, TotalFilteredItems = filteredItemsCount }; // return result; } /// /// Query Specified Language Resources ... /// /// /// /// public async Task> QueryLanguageResources( XQuery query, string language = null // ) { // // Normalize ... query = query.NormalizeQuery(DataConfiguration); // // Validate ... if (query.IsNull()) { XException.InvalidArgs.Throw(); } // XQueryResult entityResult = null; if (language.IsNullOrEmpty()) { // entityResult = await Repository.QueryAsync(query); } else { // entityResult = await Repository.ConditionalQueryAsync( e => e.Language.ToNormalString() == language.ToNormalString(), query ); } // var result = new XQueryResult { Page = entityResult.Page, PageSize = entityResult.PageSize, TotalPages = entityResult.TotalPages, TotalItems = entityResult.TotalItems, TotalFilteredPages = entityResult.TotalFilteredPages, TotalFilteredItems = entityResult.TotalFilteredItems, Items = entityResult.Items.Select(i => i.ToXStringDto()), }; // return result; } /// /// Query Locale Resources ... /// /// /// /// public async Task> QueryLocaleResources( XQuery query, string language = null // ) { // // Normalize ... query.NormalizeQuery(DataConfiguration); // // Validate ... if (query.IsNull()) { XException.InvalidArgs.Throw(); } // IEnumerable items = null; if (!language.IsNullOrEmpty()) { items = (await Repository .FindManyAsync(e => e.Language.ToNormalString() == language.ToNormalString())) .ToXLocaleResourceDtos(); } else { items = (await Repository.GetAllAsync()) .ToXLocaleResourceDtos(); } // var totalItemsCount = items.Count(); // // Apply Filter ... if (totalItemsCount > 0 && !query.Filter.IsNullOrEmpty()) { // items = items.ApplyFilter(query.Filter); } // var filteredItemsCount = items.Count(); var totalPagesCount = query.CountPages(totalItemsCount); var filteredPagesCount = query.CountPages(filteredItemsCount); // // Apply Paging/Sorting ... if (totalItemsCount > 0 && filteredItemsCount > 0) { // // Apply Sorting ... items = items.ApplySorting( query.SortBy, query.IsAscending ); // // Apply Paging ... items = items.ApplyPaging( query.Page, query.PageSize ); } // // Prepare Result ... var result = new XQueryResult { Items = items, Page = query.Page, PageSize = query.PageSize, TotalPages = totalPagesCount, TotalItems = totalItemsCount, TotalFilteredPages = filteredPagesCount, TotalFilteredItems = filteredItemsCount }; // return result; } /// /// Conditional Query Resources ... /// /// /// /// /// public async Task> ConditionalQueryResources( XQuery query, Expression> condition, string language = null ) { // // Normalize ... query = query.NormalizeQuery(DataConfiguration); // if (!language.IsNullOrEmpty()) { // // Renew and Update Condition by Language Checking ... var compiledCondition = condition.Compile(); condition = e => compiledCondition(e) && e.Language.ToNormalString() == language.ToNormalString(); } // var entityResult = await Repository.ConditionalQueryAsync(condition, query); var result = new XQueryResult { Page = entityResult.Page, PageSize = entityResult.PageSize, TotalPages = entityResult.TotalPages, TotalItems = entityResult.TotalItems, TotalFilteredPages = entityResult.TotalFilteredPages, TotalFilteredItems = entityResult.TotalFilteredItems, Items = entityResult.Items.Select(i => i.ToXStringDto()), }; // return result; } #endregion // #region Add/Update Actions ... /// /// Add Specified Resource ... /// /// /// /// /// /// public async Task Add( string resource, string value, string language = null, string connectionId = null ) { // 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, language); result = !isExists; if (!result) { XException.Duplicate.Throw(); } // // Prepare Entity to Add ... XString entity = new XString { Language = language, TranslatedValue = value, ResourceTitle = resource, }; entity = await Repository.AddAsync(entity); result = !entity.IsNullOrDefault(); if (result) { // await SendPush( action: XBaseEntityHubAction.Add.GetStringValue(), entityId: entity.Id, connectionId: connectionId ); } // return result; } /// /// Update Resource ... /// /// /// /// /// /// public async Task Update( string resource, string value, string language = null, string connectionId = null ) { // 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 ); if (!result) { XException.NotFound.Throw(); } // var entity = await Repository.FindOneAsync(e => e.ResourceTitle == resource && e.Language.ToNormalString() == language.ToNormalString() ); if (entity.IsNullOrDefault()) { XException.NotFound.Throw(); } // // Update Entity ... 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; } /// /// Add Or Update Resource ... /// /// /// /// /// /// public async Task AddOrUpdate( string resource, string value, string language = null, string connectionId = null ) { // 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 ); } else { // result = await Add( value: value, resource: resource, language: language ); } // return result; } /// /// Add Specified Resource ... /// /// /// /// public async Task AddEntity( XStringDto item, string connectionId = null ) { // // Validate ... bool isValid = !item.IsNull() && !item.ResourceTitle.IsNullOrEmpty() && !item.TranslatedValue.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Normalize ... if (item.Language.IsNullOrEmpty()) { item.Language = AppConfiguration.DefaultLanguage; } isValid = !item.Language.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Check Resource Doesn't Exists ... isValid = await IsResourceExists( resource: item.ResourceTitle, language: item.Language ); if (isValid) { XException.Duplicate.Throw(); } // var result = new XString { Language = item.Language, ResourceTitle = item.ResourceTitle, TranslatedValue = item.TranslatedValue }; result = await Repository.AddAsync(result); if (result.IsNullOrDefault()) { XException.ActionFailed.Throw(); } // await SendPush( action: XBaseEntityHubAction.Add.GetStringValue(), entityId: result.Id, connectionId: connectionId ); // return result.ToXStringDto(); } /// /// Update Specified Entity ... /// /// /// /// public async Task UpdateEntity( XStringDto item, string connectionId = null ) { // // Validate ... bool isValid = !item.IsNull() && !item.ResourceTitle.IsNullOrEmpty() && !item.TranslatedValue.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Normalize ... if (item.Language.IsNullOrEmpty()) { item.Language = AppConfiguration.DefaultLanguage; } isValid = !item.Language.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Check Resource Exists ... isValid = await IsResourceExists( resource: item.ResourceTitle, language: item.Language ); if (!isValid) { XException.NotFound.Throw(); } // var entity = await Repository.FindOneAsync(e => e.ResourceTitle == item.ResourceTitle && e.Language.ToNormalString() == item.Language.ToNormalString() ); if (entity.IsNullOrDefault()) { XException.NotFound.Throw(); } // // Update Entity ... entity.TranslatedValue = item.TranslatedValue; entity = await Repository.UpdateAsync(entity.Id, entity); if (entity.IsNullOrDefault()) { XException.ActionFailed.Throw(); } // XStringDto result = entity.ToXStringDto(); await SendPush( action: XBaseEntityHubAction.Update.GetStringValue(), entityId: entity.Id, connectionId: connectionId ); // return result; } /// /// Add Or Update Specified Entitiy ... /// /// /// /// public async Task AddOrUpdateEntity( XStringDto item, string connectionId = null ) { // // Validate ... bool isValid = !item.IsNull() && !item.ResourceTitle.IsNullOrEmpty() && !item.TranslatedValue.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Normalize ... if (item.Language.IsNullOrEmpty()) { item.Language = AppConfiguration.DefaultLanguage; } isValid = !item.Language.IsNullOrEmpty(); if (!isValid) { XException.InvalidArgs.Throw(); } // // Check Resource Exists ... var isExists = await IsResourceExists( resource: item.ResourceTitle, language: item.Language ); // XStringDto result = null; if (!isExists) { result = await AddEntity(item, connectionId); } else { result = await UpdateEntity(item, connectionId); } if (result.IsNullOrDefault()) { XException.ActionFailed.Throw(); } // return result; } /// /// Add Specified Locale Resource ... /// /// /// /// /// public async Task AddByLocaleResource( XLocaleResourceDto item, string resource, string connectionId = null ) { // // 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 ); if (isValid) { XException.Duplicate.Throw(); } // // Prepare Item to Add ... var result = new XStringDto { Language = item.Language, ResourceTitle = resource, TranslatedValue = item.Value }; result = await AddEntity(result, connectionId); // return result; } /// /// Update Specified Locale Resource ... /// /// /// /// /// public async Task UpdateByLocaleResource( XLocaleResourceDto item, string resource, string connectionId = null ) { // // 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 ); if (!isValid) { XException.NotFound.Throw(); } // var entity = await Repository.FindOneAsync(e => e.ResourceTitle == resource && e.Language.ToNormalString() == item.Language.ToNormalString() ); if (entity.IsNullOrDefault()) { XException.NotFound.Throw(); } // // Update ... entity.TranslatedValue = item.Value; entity = await Repository.UpdateAsync(entity.Id, entity); if (entity.IsNullOrDefault()) { XException.ActionFailed.Throw(); } // XStringDto result = entity.ToXStringDto(); await SendPush( action: XBaseEntityHubAction.Update.GetStringValue(), entityId: entity.Id, connectionId: connectionId ); // return result; } /// /// Add Or Update Resource By Locale ... /// /// /// /// /// public async Task AddOrUpdateByLocaleResource( XLocaleResourceDto item, string resource, string connectionId = null ) { // // 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 ); // XStringDto result = null; if (!isValid) { // result = await AddByLocaleResource( item: item, resource: resource ); } else { // result = await UpdateByLocaleResource( item: item, resource: resource ); } if (result.IsNullOrDefault()) { XException.ActionFailed.Throw(); } // return result; } /// /// Add Or Update all XResourceDto(s) Locales ... /// /// /// /// public async Task> AddByResource( XResourceDto item, string connectionId = null ) { // // 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(e, item.Resource))); // return result; } #endregion // #region Remove Actions ... /// /// Remove all Specified Language's Resources ... /// /// /// /// public async Task RemoveLanguageResources( string language, string connectionId = null ) { // // Validate ... bool isValid = !language.IsNullOrEmpty(); if (!isValid) { return; } // var entities = await Repository .FindManyAsync(e => e.Language.ToNormalString() == language.ToNormalString()); // try { // await Repository.RemoveRangeAsync(entities); // var entitieIds = entities.Select(e => e.Id); await SendCustomPush( action: XBaseEntityHubAction.DeleteMany.GetStringValue(), payLoad: entitieIds.ToJSON(camelCase: true), connectionId: connectionId ); } catch (Exception ex) { throw ex; } } /// /// Remove all Specified Resource Ids instances ... /// /// /// /// public async Task> RemoveResource( string resource, string connectionId = null ) { // // Validate ... if (resource.IsNullOrEmpty()) { XException.InvalidArgs.Throw(); } // var result = new List(); var entities = await Repository.FindManyAsync(e => e.ResourceTitle == resource); foreach (var entity in entities) { // var removed = await Repository.RemoveAsync(entity); if (!removed.IsNullOrDefault()) { result.Add(removed.ToXStringDto()); } } // if (result.HasChild()) { // var ids = result.Select(i => i.Id); await SendCustomPush( action: XBaseEntityHubAction.DeleteMany.GetStringValue(), payLoad: ids.ToJSON(camelCase: true), connectionId: connectionId ); } // return result; } /// /// Remove Specified Resource ... /// /// /// /// /// public async Task Remove( string resource, string language = null, string connectionId = null ) { // 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 ); if (!result) { return result; } // // Retrieve Entity ... var entity = await Repository.FindOneAsync(e => e.ResourceTitle == resource && e.Language.ToNormalString() == language.ToNormalString() ); result = !entity.IsNullOrDefault(); if (!result) { return result; } // // 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; } /// /// Remove all Resource of Specified XResourceDto ... /// /// /// /// public async Task RemoveByResource( XResourceDto item, string connectionId = null ) { // 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 ); } } #endregion // #region Hub Actions ... /// /// Send Specified Hub Action Notifications ... /// /// /// /// public async Task SendPush( string action, int entityId, string connectionId = null ) { // var actions = new List { XBaseEntityHubAction.Add.GetStringValue(), XBaseEntityHubAction.Update.GetStringValue(), XBaseEntityHubAction.Delete.GetStringValue(), XBaseEntityHubAction.AddMany.GetStringValue(), XBaseEntityHubAction.DeleteMany.GetStringValue(), XBaseEntityHubAction.UpdateMany.GetStringValue(), XBaseEntityHubAction.AddOrUpdate.GetStringValue(), }; // // Validate ... var isValid = entityId > 0 && !Hub.IsNull() && !action.IsNullOrEmpty() && actions.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.ToJSON(camelCase: true), connectionId); } /// /// Send Custom Push Message ... /// /// /// /// /// public async Task SendCustomPush( string action, string payLoad, string connectionId = null ) { // var customActions = new List { XBaseEntityHubAction.DeleteMany.GetStringValue(), }; // // Validate ... var isValid = !Hub.IsNull() && !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 } }