mirror of https://github.com/abpframework/abp.git
committed by
GitHub
37 changed files with 637 additions and 45 deletions
@ -0,0 +1,16 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Volo.CmsKit.Admin.Tags |
|||
{ |
|||
public class EntityTagCreateDto |
|||
{ |
|||
[Required] |
|||
public string TagName { get; set; } |
|||
|
|||
[Required] |
|||
public string EntityType { get; set; } |
|||
|
|||
[Required] |
|||
public string EntityId { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Volo.CmsKit.Admin.Tags |
|||
{ |
|||
public class EntityTagRemoveDto |
|||
{ |
|||
[Required] |
|||
public Guid TagId { get; set; } |
|||
|
|||
[Required] |
|||
public string EntityType { get; set; } |
|||
|
|||
[Required] |
|||
public string EntityId { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.CmsKit.Admin.Tags |
|||
{ |
|||
public interface IEntityTagAdminAppService |
|||
{ |
|||
Task AddTagToEntityAsync(EntityTagCreateDto input); |
|||
|
|||
Task RemoveTagFromEntityAsync(EntityTagRemoveDto input); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
namespace Volo.CmsKit.Admin.Tags |
|||
{ |
|||
public class TagDefinitionDto |
|||
{ |
|||
public TagDefinitionDto() |
|||
{ |
|||
} |
|||
public TagDefinitionDto(string entityType, string displayName) |
|||
{ |
|||
EntityType = entityType; |
|||
DisplayName = displayName; |
|||
} |
|||
|
|||
public string EntityType { get; set; } |
|||
|
|||
public string DisplayName { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.CmsKit.Admin.Tags; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit.Admin.Application.Volo.CmsKit.Admin.Tags |
|||
{ |
|||
public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService |
|||
{ |
|||
protected ITagDefinitionStore _tagDefinitionStore; |
|||
protected IEntityTagManager _entityTagManager; |
|||
protected ITagManager _tagManager; |
|||
|
|||
public EntityTagAdminAppService( |
|||
ITagDefinitionStore tagDefinitionStore, |
|||
IEntityTagManager entityTagManager, |
|||
ITagManager tagManager) |
|||
{ |
|||
_tagDefinitionStore = tagDefinitionStore; |
|||
_entityTagManager = entityTagManager; |
|||
_tagManager = tagManager; |
|||
} |
|||
|
|||
public async Task AddTagToEntityAsync(EntityTagCreateDto input) |
|||
{ |
|||
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType); |
|||
|
|||
await CheckPolicyAsync(definition.CreatePolicy); |
|||
|
|||
var tag = await _tagManager.GetOrAddAsync(input.EntityType, input.TagName, CurrentTenant?.Id); |
|||
|
|||
await _entityTagManager.AddTagToEntityAsync( |
|||
tag.Id, |
|||
input.EntityType, |
|||
input.EntityId, |
|||
CurrentTenant?.Id); |
|||
} |
|||
|
|||
public async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input) |
|||
{ |
|||
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType); |
|||
|
|||
await CheckPolicyAsync(definition.DeletePolicy); |
|||
|
|||
await _entityTagManager.RemoveTagFromEntityAsync( |
|||
input.TagId, |
|||
input.EntityType, |
|||
input.EntityId, |
|||
CurrentTenant?.Id); |
|||
} |
|||
} |
|||
} |
|||
@ -1,16 +1,12 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.CmsKit.Reactions; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit |
|||
{ |
|||
public class CmsKitOptions |
|||
{ |
|||
[NotNull] |
|||
public ReactionDefinitionDictionary Reactions { get; } |
|||
|
|||
public CmsKitOptions() |
|||
{ |
|||
Reactions = new ReactionDefinitionDictionary(); |
|||
} |
|||
public ReactionDefinitionDictionary Reactions { get; } = new ReactionDefinitionDictionary(); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,32 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace Volo.CmsKit.Domain.Volo.CmsKit |
|||
{ |
|||
public abstract class PolicySpecifiedDefinition |
|||
{ |
|||
protected PolicySpecifiedDefinition() |
|||
{ |
|||
} |
|||
|
|||
public PolicySpecifiedDefinition( |
|||
[CanBeNull] string createPolicy = null, |
|||
[CanBeNull] string updatePolicy = null, |
|||
[CanBeNull] string deletePolicy = null) |
|||
{ |
|||
CreatePolicy = createPolicy; |
|||
DeletePolicy = deletePolicy; |
|||
UpdatePolicy = updatePolicy; |
|||
} |
|||
|
|||
[CanBeNull] |
|||
public virtual string CreatePolicy { get; set; } |
|||
|
|||
[CanBeNull] |
|||
public virtual string UpdatePolicy { get; set; } |
|||
|
|||
[CanBeNull] |
|||
public virtual string DeletePolicy { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public class CmsKitTagOptions |
|||
{ |
|||
[NotNull] |
|||
public TagEntityTypeDefinitionDictionary EntityTypes { get; } = new TagEntityTypeDefinitionDictionary(); |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
using JetBrains.Annotations; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public class DefaultTagDefinitionStore : ITagDefinitionStore, ITransientDependency |
|||
{ |
|||
private readonly CmsKitTagOptions options; |
|||
|
|||
public DefaultTagDefinitionStore(IOptions<CmsKitTagOptions> options) |
|||
{ |
|||
this.options = options.Value; |
|||
} |
|||
|
|||
public virtual Task<TagEntityTypeDefiniton> GetTagEntityTypeDefinitionsAsync([NotNull] string entityType) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
|
|||
var result = options.EntityTypes.GetOrDefault(entityType) ?? throw new EntityNotTaggableException(entityType); |
|||
|
|||
return Task.FromResult(result); |
|||
} |
|||
|
|||
public virtual Task<List<TagEntityTypeDefiniton>> GetTagDefinitionsAsync() |
|||
{ |
|||
return Task.FromResult(options.EntityTypes.Values.ToList()); |
|||
} |
|||
|
|||
public virtual Task<bool> IsDefinedAsync([NotNull] string entityType) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
return Task.FromResult(options.EntityTypes.ContainsKey(entityType)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
[Serializable] |
|||
public class EntityNotTaggableException : BusinessException |
|||
{ |
|||
public EntityNotTaggableException( |
|||
string code = null, |
|||
string message = null, |
|||
string details = null, |
|||
Exception innerException = null, |
|||
LogLevel logLevel = LogLevel.Warning) |
|||
: base(code, message, details, innerException, logLevel) |
|||
{ |
|||
} |
|||
|
|||
public EntityNotTaggableException(string entityType) |
|||
{ |
|||
Code = CmsKitErrorCodes.Tags.EntityNotTaggable; |
|||
WithData(nameof(Tag.EntityType), entityType); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Services; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public class EntityTagManager : DomainService, IEntityTagManager |
|||
{ |
|||
protected readonly IEntityTagRepository _entityTagRepository; |
|||
protected readonly ITagDefinitionStore _tagDefinitionStore; |
|||
|
|||
public EntityTagManager( |
|||
IEntityTagRepository entityTagRepository, |
|||
ITagDefinitionStore tagDefinitionStore) |
|||
{ |
|||
_entityTagRepository = entityTagRepository; |
|||
_tagDefinitionStore = tagDefinitionStore; |
|||
} |
|||
|
|||
public async Task<EntityTag> AddTagToEntityAsync( |
|||
[NotNull] Guid tagId, |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
if (!await _tagDefinitionStore.IsDefinedAsync(entityType)) |
|||
{ |
|||
throw new EntityNotTaggableException(entityType); |
|||
} |
|||
|
|||
var entityTag = new EntityTag(tagId, entityId, tenantId); |
|||
|
|||
return await _entityTagRepository.InsertAsync(entityTag, cancellationToken: cancellationToken); |
|||
} |
|||
|
|||
public async Task RemoveTagFromEntityAsync( |
|||
[NotNull] Guid tagId, |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var entityTag = await _entityTagRepository.FindAsync(tagId, entityId, tenantId, cancellationToken); |
|||
|
|||
await _entityTagRepository.DeleteAsync(entityTag); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public interface IEntityTagManager |
|||
{ |
|||
Task<EntityTag> AddTagToEntityAsync( |
|||
[NotNull] Guid tagId, |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default); |
|||
|
|||
Task RemoveTagFromEntityAsync( |
|||
[NotNull] Guid tagId, |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -1,9 +1,17 @@ |
|||
using Volo.Abp.Domain.Repositories; |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public interface IEntityTagRepository : IBasicRepository<EntityTag> |
|||
{ |
|||
|
|||
Task<EntityTag> FindAsync( |
|||
[NotNull] Guid tagId, |
|||
[NotNull] string entityId, |
|||
[CanBeNull] Guid? tenantId, |
|||
CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public interface ITagDefinitionStore |
|||
{ |
|||
Task<List<TagEntityTypeDefiniton>> GetTagDefinitionsAsync(); |
|||
|
|||
Task<TagEntityTypeDefiniton> GetTagEntityTypeDefinitionsAsync([NotNull] string entityType); |
|||
|
|||
Task<bool> IsDefinedAsync([NotNull] string entityType); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public class TagEntityTypeDefinitionDictionary : Dictionary<string, TagEntityTypeDefiniton> |
|||
{ |
|||
public void AddOrReplace( |
|||
[NotNull] string entityType, |
|||
[CanBeNull] ILocalizableString displayName = null, |
|||
[CanBeNull] string createPolicy = null, |
|||
[CanBeNull] string updatePolicy = null, |
|||
[CanBeNull] string deletePolicy = null |
|||
) |
|||
{ |
|||
this[entityType] = new TagEntityTypeDefiniton(entityType, displayName, createPolicy, updatePolicy, deletePolicy); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Localization; |
|||
using Volo.CmsKit.Domain.Volo.CmsKit; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public class TagEntityTypeDefiniton : PolicySpecifiedDefinition |
|||
{ |
|||
public string EntityType { get; } |
|||
|
|||
[CanBeNull] |
|||
public virtual ILocalizableString DisplayName { get; } |
|||
|
|||
public TagEntityTypeDefiniton() |
|||
{ |
|||
} |
|||
|
|||
public TagEntityTypeDefiniton( |
|||
[NotNull] string entityType, |
|||
[CanBeNull] ILocalizableString displayName = null, |
|||
[CanBeNull] string createPolicy = null, |
|||
[CanBeNull] string updatePolicy = null, |
|||
[CanBeNull] string deletePolicy = null) : base(createPolicy, updatePolicy, deletePolicy) |
|||
{ |
|||
EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
|
|||
DisplayName = displayName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
using Shouldly; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Guids; |
|||
using Xunit; |
|||
|
|||
namespace Volo.CmsKit.Tags |
|||
{ |
|||
public class EntityTagManager_Tests : CmsKitDomainTestBase |
|||
{ |
|||
private readonly CmsKitTestData _cmsKitTestData; |
|||
private readonly IEntityTagManager _entityTagManager; |
|||
private readonly ITagRepository _tagRepository; |
|||
private readonly IGuidGenerator _guidGenerator; |
|||
|
|||
public EntityTagManager_Tests() |
|||
{ |
|||
_cmsKitTestData = GetRequiredService<CmsKitTestData>(); |
|||
_entityTagManager = GetRequiredService<IEntityTagManager>(); |
|||
_tagRepository = GetRequiredService<ITagRepository>(); |
|||
_guidGenerator = GetRequiredService<IGuidGenerator>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task AddTagToEntityAsync_ShouldAdd_WhenEverythingCorrect() |
|||
{ |
|||
var tag = await _tagRepository.InsertAsync(new Tag(_guidGenerator.Create(), _cmsKitTestData.EntityType1, "My Test Tag #1")); |
|||
|
|||
var entityTag = await _entityTagManager.AddTagToEntityAsync(tag.Id, _cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1); |
|||
|
|||
entityTag.ShouldNotBeNull(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task AddTagToEntity_ShouldThrowNotTaggable_WithNotConfiguredEntityType() |
|||
{ |
|||
var entityType = "Not.Configured.EntityType"; |
|||
|
|||
var exception = Should.Throw<EntityNotTaggableException>(async () => |
|||
await _entityTagManager.AddTagToEntityAsync(_cmsKitTestData.TagId_1, entityType, _cmsKitTestData.EntityId1) |
|||
); |
|||
|
|||
exception.ShouldNotBeNull(); |
|||
exception.Data[nameof(Tag.EntityType)].ShouldBe(entityType); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task RemoveTagFromEntityAsync_ShouldRemove_WhenEverythingCorrect() |
|||
{ |
|||
var tagToDelete = (await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1)) |
|||
.First(); |
|||
|
|||
await _entityTagManager.RemoveTagFromEntityAsync(tagToDelete.Id, tagToDelete.EntityType, _cmsKitTestData.EntityId1); |
|||
|
|||
var tags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1); |
|||
|
|||
tags.ShouldNotContain(x => x.Id == tagToDelete.Id); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue