diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index b4885d8..8bb6868 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -78,8 +78,8 @@ namespace xTagService.DI var pushHelper = new XPushServiceHelper(); // - pushHelper.AddHub("stringDto"); - pushHelper.AddHub("stringEntity"); + pushHelper.AddHub("tagDto"); + pushHelper.AddHub("tagEntity"); // app.UseXPushService(pushHelper); diff --git a/Interfaces/IXBaseProvidedHasTag.cs b/Interfaces/IXBaseProvidedHasTag.cs new file mode 100644 index 0000000..192df76 --- /dev/null +++ b/Interfaces/IXBaseProvidedHasTag.cs @@ -0,0 +1,12 @@ +using xModels.Base; +using xPushService.Base; +using xPushService.Interfaces; + +namespace xTagService.Interfaces +{ + public interface IXBaseProvidedHasTag : IXBaseProvided, IXTagProvided + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { } +} \ No newline at end of file diff --git a/Interfaces/IXTagProvided.cs b/Interfaces/IXTagProvided.cs new file mode 100644 index 0000000..40320e6 --- /dev/null +++ b/Interfaces/IXTagProvided.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xIdentityModels.Models; +using xModels.Base; +using xPushService.Base; + +namespace xTagService.Interfaces +{ + /// + /// a Tag Provided Service is a Model Provider Service which + /// can Contains Tags ... + /// + public interface IXTagProvided + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + /// + /// Attach Tag to Specified Item ... + /// + /// + /// + /// + /// + /// + /// + Task AttachTag( + TKey id, + string tag, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Detach Tag of Specified Item ... + /// + /// + /// + /// + /// + /// + /// + Task DetachTag( + TKey id, + string tag, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Attach Tags to Specified Item ... + /// + /// + /// + /// + /// + /// + /// + Task AttachTags( + TKey id, + IEnumerable tags, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Detach Tags of Specified Item ... + /// + /// + /// + /// + /// + /// + /// + Task DetachTags( + TKey id, + IEnumerable tags, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Detach all Attached Tags of Specified Item ... + /// + /// + /// + /// + /// + /// + Task DetachTags( + TKey id, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Get Specified Item Tags ... + /// + /// + /// + /// + Task> GetTags( + TKey id, + CancellationToken cancellationToken = default + ); + } +} \ No newline at end of file diff --git a/Interfaces/IXTagProvidedController.cs b/Interfaces/IXTagProvidedController.cs new file mode 100644 index 0000000..765bfb2 --- /dev/null +++ b/Interfaces/IXTagProvidedController.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using xModels.Base; +using xPushService.Base; + +namespace xTagService.Interfaces +{ + public interface IXTagProvidedController + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + /// + /// Attach Tag to Specified Item ... + /// + /// + /// + /// + /// + [HttpPost("{id}/tags/attach")] + Task AttachTag( + [FromRoute] TKey id, + [FromBody] XBaseValueContainer tag, + CancellationToken cancellationToken = default + ); + + /// + /// Detach Tag of Specified Item ... + /// + /// + /// + /// + /// + [HttpPost("{id}/tags/detach")] + Task DetachTag( + [FromRoute] TKey id, + [FromBody] XBaseValueContainer tag, + CancellationToken cancellationToken = default + ); + + /// + /// Attach Tags to Specified Item ... + /// + /// + /// + /// + /// + [HttpPost("{id}/tags/attachs")] + Task AttachTags( + [FromRoute] TKey id, + [FromBody] XBaseRangeRequest tags, + CancellationToken cancellationToken = default + ); + + /// + /// Detach Tags of Specified Item ... + /// + /// + /// + /// + /// + [HttpPost("{id}/tags/detachs")] + Task DetachTags( + [FromRoute] TKey id, + [FromBody] XBaseRangeRequest tags = null, + CancellationToken cancellationToken = default + ); + + /// + /// Get Specified Item Tags ... + /// + /// + /// + /// + [HttpGet("{id}/tags")] + Task>> GetTags( + [FromRoute] TKey id, + CancellationToken cancellationToken = default + ); + } +} \ No newline at end of file diff --git a/Providers/XBaseProvidedHasTag.cs b/Providers/XBaseProvidedHasTag.cs new file mode 100644 index 0000000..25d6f91 --- /dev/null +++ b/Providers/XBaseProvidedHasTag.cs @@ -0,0 +1,723 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using xCommons.Extensions; +using xIdentityModels.Models; +using xModels.Base; +using xPushService.Base; +using xPushService.Interfaces; +using xTagService.Interfaces; +using xIdentityModels.Extensions; +using System.Threading; +using xExceptions.Constants; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Query; +using xModels.Dtos; + +namespace xTagService.Providers +{ + public abstract class XBaseProvidedHasTag : IXBaseProvidedHasTag + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + private readonly string[] permittedRoles; + private readonly IXBaseTagProvider tagProvider; + private readonly IXBaseDtoProvider provider; + + protected XBaseProvidedHasTag( + IXBaseTagProvider tagProvider, + IXBaseDtoProvider provider, + string[] permittedRoles = null + ) + { + this.provider = provider; + this.tagProvider = tagProvider; + this.permittedRoles = permittedRoles; + } + + /// + /// Check an Items is Owned for User or not ... + /// + /// + /// + /// + public abstract bool IsOwned( + TDto item, + XUserClaimsInfoDto userInfo + ); + public abstract bool IsOwned( + TEntity item, + XUserClaimsInfoDto userInfo + ); + + /// + /// Check User Has Permission for Manipulate Data or not ... + /// + /// + /// + public bool HasPermision( + XUserClaimsInfoDto userInfo + ) + { + // + var result = + !userInfo.IsNullOrDefault() && + userInfo.HasAccess(permittedRoles); + + // + return result; + } + + // + #region Tag ... + /// + /// Attach Tag to Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AttachTag( + TKey id, + string tag, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tag.IsNullOrEmpty() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var item = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + isValid = + !item.IsNullOrDefault() && + (IsOwned(item, userInfo) || + HasPermision(userInfo)); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + try + { + // + await tagProvider.AddReference( + tag: tag, + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + catch { } + } + + /// + /// Detach Tag fro Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task DetachTag( + TKey id, + string tag, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tag.IsNullOrEmpty() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var item = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + isValid = + !item.IsNullOrDefault() && + (IsOwned(item, userInfo) || + HasPermision(userInfo)); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + try + { + // + await tagProvider.RemoveReference( + tag: tag, + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + catch { } + } + + /// + /// Attach Tags for Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AttachTags( + TKey id, + IEnumerable tags, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tags.IsNull() && + tags.HasChild(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Loop through Tags ... + foreach (var tag in tags) + { + // + // Check Cancellation Token ... + if (cancellationToken.IsCancellationRequested) + { + break; + } + + // + await AttachTag( + id: id, + tag: tag, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + } + + /// + /// Detach Tags for Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task DetachTags( + TKey id, + IEnumerable tags, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tags.IsNull() && + tags.HasChild(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Loop through Tags ... + foreach (var tag in tags) + { + // + // Check Cancellation Token ... + if (cancellationToken.IsCancellationRequested) + { + break; + } + + // + await DetachTag( + id: id, + tag: tag, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + } + + /// + /// Detach all Attached Tags for Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task DetachTags( + TKey id, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var item = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + isValid = + !item.IsNullOrDefault() && + (IsOwned(item, userInfo) || + HasPermision(userInfo)); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + try + { + // + await tagProvider.RemoveReferences( + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + catch { } + } + + /// + /// Get Specified Model's Item ... + /// + /// + /// + /// + public virtual async Task> GetTags( + TKey id, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = !id.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + isValid = await provider.IsExistsAsync( + id: id, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = (await tagProvider.GetAllReferences( + providedForId: id, + cancellationToken: cancellationToken + )) + .Select(x => x.Tag) + .Distinct() + .ToList(); + + // + return result; + } + #endregion + + // + #region Provided ... + /// + /// Get Specified Item by ID ... + /// + /// + /// + /// + /// + public virtual async Task Get( + TKey id, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Get All Exists Items ... + /// + /// + /// + /// + /// + public virtual async Task> GetAll( + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.GetAllAsync( + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// find an item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + public virtual async Task FindOne( + Expression> predicate, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.FindOneAsync( + predicate: predicate, + ignoreSoftDeleteds: true, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public virtual async Task> FindMany( + Expression> predicate, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.FindManyAsync( + predicate: predicate, + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> Query( + XQuery query, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.QueryAsync( + query: query, + predicate: predicate, + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// retrieve Owned Items based on XQuery Pagination structure ... + /// if supported ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> QueryOwned( + XQuery query, + XUserClaimsInfoDto userInfo = null, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + Expression> predicateor = null; + if (!predicate.IsNull()) + { + // + var predicateFnc = predicate.Compile(); + predicateor = x => + predicateFnc(x) && + IsOwned(x, userInfo); + } + else + { + predicateor = x => IsOwned(x, userInfo); + } + + // + var result = await provider.QueryAsync( + query: query, + predicate: predicateor, + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Add an item values ... + /// + /// + /// + /// + /// + /// + public virtual async Task Add( + TDto item, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.AddAsync( + item: item, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Update an item values ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task Update( + TKey id, + TDto item, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Permission ... + var hasPermission = + IsOwned(item, userInfo) || + HasPermision(userInfo); + if (!hasPermission) + { + XException.NotAllowed.Throw(); + } + + // + var result = await provider.UpdateAsync( + id: id, + item: item, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// remove an Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Remove( + TKey id, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Permission ... + var item = await Get( + id: id, + cancellationToken: cancellationToken + ); + var hasPermission = + IsOwned(item, userInfo) || + HasPermision(userInfo); + if (!hasPermission) + { + XException.NotAllowed.Throw(); + } + + // + var result = await provider.RemoveAsync( + id: id, + saveChanges: true, + softDelete: false, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// count all exists Items ... + /// + /// + /// + public virtual async Task Count( + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.CountAsync( + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + public virtual async Task IsExists( + TKey id, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.IsExistsAsync( + id: id, + cancellationToken: cancellationToken + ); + + // + return result; + } + #endregion + } +} \ No newline at end of file diff --git a/Providers/XBaseTagProvided.cs b/Providers/XBaseTagProvided.cs new file mode 100644 index 0000000..a0b7137 --- /dev/null +++ b/Providers/XBaseTagProvided.cs @@ -0,0 +1,384 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xCommons.Extensions; +using xIdentityModels.Models; +using xModels.Base; +using xPushService.Base; +using xPushService.Interfaces; +using xTagService.Interfaces; +using xIdentityModels.Extensions; +using xExceptions.Constants; +using System.Linq; + +namespace xTagService.Providers +{ + public abstract class XBaseTagProvided : IXTagProvided + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + private readonly string[] permittedRoles; + private readonly IXBaseTagProvider tagProvider; + private readonly IXBaseDtoProvider provider; + + protected XBaseTagProvided( + IXBaseTagProvider tagProvider, + IXBaseDtoProvider provider, + string[] permittedRoles = null + ) + { + this.provider = provider; + this.tagProvider = tagProvider; + this.permittedRoles = permittedRoles; + } + + /// + /// Check an Items is Owned for User or not ... + /// + /// + /// + /// + public abstract bool IsOwned( + TDto item, + XUserClaimsInfoDto userInfo + ); + public abstract bool IsOwned( + TEntity item, + XUserClaimsInfoDto userInfo + ); + + /// + /// Check User Has Permission for Manipulate Data or not ... + /// + /// + /// + public bool HasPermision( + XUserClaimsInfoDto userInfo + ) + { + // + var result = + !userInfo.IsNullOrDefault() && + userInfo.HasAccess(permittedRoles); + + // + return result; + } + + // + #region Actions ... + /// + /// Attach Tag to Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AttachTag( + TKey id, + string tag, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tag.IsNullOrEmpty() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var item = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + isValid = + !item.IsNullOrDefault() && + (IsOwned(item, userInfo) || + HasPermision(userInfo)); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + try + { + // + await tagProvider.AddReference( + tag: tag, + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + catch { } + } + + /// + /// Detach Tag fro Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task DetachTag( + TKey id, + string tag, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tag.IsNullOrEmpty() && + !userInfo.IsNullOrDefault(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var item = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + isValid = + !item.IsNullOrDefault() && + (IsOwned(item, userInfo) || + HasPermision(userInfo)); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + try + { + // + await tagProvider.RemoveReference( + tag: tag, + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + catch { } + } + + /// + /// Attach Tags for Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AttachTags( + TKey id, + IEnumerable tags, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tags.IsNull() && + tags.HasChild(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Loop through Tags ... + foreach (var tag in tags) + { + // + // Check Cancellation Token ... + if (cancellationToken.IsCancellationRequested) + { + break; + } + + // + await AttachTag( + id: id, + tag: tag, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + } + + /// + /// Detach Tags for Specified Item ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task DetachTags( + TKey id, + IEnumerable tags, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull() && + !tags.IsNull() && + tags.HasChild(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Loop through Tags ... + foreach (var tag in tags) + { + // + // Check Cancellation Token ... + if (cancellationToken.IsCancellationRequested) + { + break; + } + + // + await DetachTag( + id: id, + tag: tag, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + } + + /// + /// Detach all Attached Tags for Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task DetachTags( + TKey id, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = + !id.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var item = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + isValid = + !item.IsNullOrDefault() && + (IsOwned(item, userInfo) || + HasPermision(userInfo)); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + try + { + // + await tagProvider.RemoveReferences( + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + catch { } + } + + /// + /// Get Specified Model's Item ... + /// + /// + /// + /// + public virtual async Task> GetTags( + TKey id, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = !id.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + isValid = await provider.IsExistsAsync( + id: id, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = (await tagProvider.GetAllReferences( + providedForId: id, + cancellationToken: cancellationToken + )) + .Select(x => x.Tag) + .Distinct() + .ToList(); + + // + return result; + } + #endregion + } +} \ No newline at end of file diff --git a/Providers/Entities/XTagSeederBase.cs b/Providers/XTagSeederBase.cs similarity index 93% rename from Providers/Entities/XTagSeederBase.cs rename to Providers/XTagSeederBase.cs index 1daf6e2..9bef85f 100644 --- a/Providers/Entities/XTagSeederBase.cs +++ b/Providers/XTagSeederBase.cs @@ -4,7 +4,7 @@ using xDataService.Providers; using xTagService.Interfaces; using xTagService.Models.Entities; -namespace xTagService.Providers.Entities +namespace xTagService.Providers { public abstract class XTagSeederBase : XBaseDbSeeder, IXTagSeeder {