diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentCreateDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentCreateDto.cs new file mode 100644 index 0000000000..6729203c8e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentCreateDto.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; +using Volo.CmsKit.Contents; + +namespace Volo.CmsKit.Admin.Contents +{ + public class ContentCreateDto + { + [Required] + [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxEntityTypeLength))] + public string EntityType { get; set; } + + [Required] + [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxEntityIdLength))] + public string EntityId { get; set; } + + [Required] + [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxValueLength))] + public string Value { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs index aa7a4650b1..69ece26ca4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs @@ -5,6 +5,10 @@ namespace Volo.CmsKit.Admin.Contents { public class ContentDto : EntityDto { + public string EntityType { get; set; } + + public string EntityId { get; set; } + public string Value { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListInput.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListInput.cs new file mode 100644 index 0000000000..73df63558b --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListInput.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Application.Dtos; + +namespace Volo.CmsKit.Admin.Contents +{ + public class ContentGetListInput : PagedAndSortedResultRequestDto + { + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentUpdateDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentUpdateDto.cs new file mode 100644 index 0000000000..1164b4eecc --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentUpdateDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; +using Volo.CmsKit.Contents; + +namespace Volo.CmsKit.Admin.Contents +{ + public class ContentUpdateDto + { + [Required] + [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxValueLength))] + public string Value { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs new file mode 100644 index 0000000000..02b25aa16d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Application.Services; +using Volo.CmsKit.Admin.Contents; + +namespace Volo.CmsKit.Admin.Contents +{ + public interface IContentAdminAppService + : ICrudAppService< + ContentDto, + Guid, + ContentGetListInput, + ContentCreateDto, + ContentUpdateDto> + { + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs index 507b1c276f..34c7947d67 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs @@ -12,6 +12,14 @@ namespace Volo.CmsKit.Permissions { var cmsGroup = context.GetGroupOrNull(CmsKitAdminPermissions.GroupName) ?? context.AddGroup(CmsKitAdminPermissions.GroupName, L("Permission:CmsKit")); + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + var contentGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Contents.Default, L("Permission:Contents")); + contentGroup.AddChild(CmsKitAdminPermissions.Contents.Create, L("Permission:Contents.Create")); + contentGroup.AddChild(CmsKitAdminPermissions.Contents.Update, L("Permission:Contents.Update")); + contentGroup.AddChild(CmsKitAdminPermissions.Contents.Delete, L("Permission:Contents.Delete")); + } if (GlobalFeatureManager.Instance.IsEnabled()) { var tagGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Tags.Default, L("Permission:TagManagement")); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs index 26daeb0b01..55bffff67f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs @@ -12,5 +12,13 @@ namespace Volo.CmsKit.Permissions public const string Update = Default + ".Update"; public const string Delete = Default + ".Delete"; } + + public static class Contents + { + public const string Default = GroupName + ".Contents"; + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs index e1062daa92..4b7a6eb58f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Volo.CmsKit.Admin.Contents; using Volo.CmsKit.Admin.Pages; +using Volo.CmsKit.Contents; using Volo.CmsKit.Pages; namespace Volo.CmsKit.Admin @@ -9,6 +11,10 @@ namespace Volo.CmsKit.Admin public CmsKitAdminApplicationAutoMapperProfile() { CreateMap(); + + CreateMap(MemberList.Destination); + CreateMap(MemberList.Source); + CreateMap(MemberList.Source); } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs new file mode 100644 index 0000000000..4695339fd7 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Repositories; +using Volo.CmsKit.Contents; +using Volo.CmsKit.Domain.Volo.CmsKit.Contents; +using Volo.CmsKit.Permissions; + +namespace Volo.CmsKit.Admin.Contents +{ + [Authorize(CmsKitAdminPermissions.Contents.Default)] + public class ContentAdminAppService : + CrudAppService< + Content, + ContentDto, + Guid, + ContentGetListInput, + ContentCreateDto, + ContentUpdateDto + >, IContentAdminAppService + { + protected IContentManager ContentManager { get; } + + protected IContentRepository ContentRepository { get; } + + public ContentAdminAppService( + IRepository repository, + IContentManager contentManager, + IContentRepository contentRepository) : base(repository) + { + ContentManager = contentManager; + + GetListPolicyName = CmsKitAdminPermissions.Contents.Default; + GetPolicyName = CmsKitAdminPermissions.Contents.Default; + CreatePolicyName = CmsKitAdminPermissions.Contents.Create; + UpdatePolicyName = CmsKitAdminPermissions.Contents.Update; + DeletePolicyName = CmsKitAdminPermissions.Contents.Delete; + ContentRepository = contentRepository; + } + + [Authorize(CmsKitAdminPermissions.Contents.Create)] + public override async Task CreateAsync(ContentCreateDto input) + { + var entity = new Content( + GuidGenerator.Create(), + input.EntityType, + input.EntityId, + input.Value, + CurrentTenant?.Id); + + await ContentManager.InsertAsync(entity); + + return MapToGetListOutputDto(entity); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs new file mode 100644 index 0000000000..935606b686 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Admin.Contents; +using Volo.CmsKit.GlobalFeatures; +using Volo.CmsKit.Permissions; + +namespace Volo.CmsKit.Admin.Contents +{ + [Authorize(CmsKitAdminPermissions.Contents.Default)] + [RequiresGlobalFeature(typeof(ContentsFeature))] + [RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] + [Area("cms-kit")] + [Route("api/cms-kit-admin/contents")] + public class ContentAdminController : CmsKitAdminController, IContentAdminAppService + { + protected IContentAdminAppService ContentAdminAppService { get; } + + public ContentAdminController(IContentAdminAppService contentAdminAppService) + { + ContentAdminAppService = contentAdminAppService; + } + + [HttpPost] + [Authorize(CmsKitAdminPermissions.Contents.Create)] + public Task CreateAsync(ContentCreateDto input) + { + return ContentAdminAppService.CreateAsync(input); + } + + [HttpDelete("{id}")] + [Authorize(CmsKitAdminPermissions.Contents.Delete)] + public Task DeleteAsync(Guid id) + { + return ContentAdminAppService.DeleteAsync(id); + } + + [HttpGet("{id}")] + [Authorize(CmsKitAdminPermissions.Contents.Default)] + public Task GetAsync(Guid id) + { + return ContentAdminAppService.GetAsync(id); + } + + [HttpGet] + [Authorize(CmsKitAdminPermissions.Contents.Default)] + public Task> GetListAsync(ContentGetListInput input) + { + return ContentAdminAppService.GetListAsync(input); + } + + [HttpPut] + [Authorize(CmsKitAdminPermissions.Contents.Update)] + public Task UpdateAsync(Guid id, ContentUpdateDto input) + { + return ContentAdminAppService.UpdateAsync(id, input); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs index 76ba39c3f2..4b57a5a52e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs @@ -3,5 +3,6 @@ public static class CmsKitErrorCodes { public const string TagAlreadyExist = "CmsKit:0001"; + public const string ContentAlreadyExist = "CmsKit:0002"; } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Contents/ContentConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Contents/ContentConsts.cs index 758a29e81f..d6d69a6a39 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Contents/ContentConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Contents/ContentConsts.cs @@ -10,6 +10,6 @@ namespace Volo.CmsKit.Contents public static int MaxEntityIdLength { get; set; } = CmsEntityConsts.MaxEntityIdLength; // TODO: consider - public static int MaxValueLength = int.MaxValue; + public static int MaxValueLength { get; set; } = int.MaxValue; } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 27c5b3fad0..8ad45af0ff 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -1,6 +1,7 @@ { "culture": "en", "texts": { + "CmsKit:0002": "Content already exists!", "CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.", "Comments": "Comments", "Delete": "Delete", @@ -11,6 +12,10 @@ "Menu:CMS": "CMS", "MessageDeletionConfirmationMessage": "This comment will be deleted completely.", "Permission:CmsKit": "CmsKit", + "Permission:Contents": "Content Management", + "Permission:Contents.Create": "Create Content", + "Permission:Contents.Delete": "Delete Content", + "Permission:Contents.Update": "Update Content", "Permission:TagManagement": "Tag Management", "Permission:TagManagement.Create": "Create Tag", "Permission:TagManagement.Delete": "Delete Tag", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index 2433aca4ac..c081b86fc7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json @@ -1,6 +1,7 @@ { "culture": "tr", "texts": { + "CmsKit:0002": "İçerik zaten mevcut!", "CommentAuthorizationExceptionMessage": "Bu yorumları görebilmek için yetki gerekir.", "Comments": "Yorumlar", "Delete": "Sil", @@ -11,6 +12,10 @@ "Menu:CMS": "CMS", "MessageDeletionConfirmationMessage": "Bu yorum tamamen silinecektir", "Permission:CmsKit": "CmsKit", + "Permission:Contents": "İçerik Yönetimi", + "Permission:Contents.Create": "İçerik Oluşturma", + "Permission:Contents.Delete": "İçerik Silme", + "Permission:Contents.Update": "İçerik Güncelleme", "Permission:TagManagement": "Etiket Yönetimi", "Permission:TagManagement.Create": "Etiket Oluşturma", "Permission:TagManagement.Delete": "Etiket Silme", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs index 6f4175daad..e2d4a2a4ac 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs @@ -8,9 +8,9 @@ namespace Volo.CmsKit.Contents { public class Content : FullAuditedAggregateRoot, IMultiTenant { - public virtual Guid? TenantId { get; set; } + public virtual Guid? TenantId { get; protected set; } - public virtual string EntityType { get; set; } + public virtual string EntityType { get; protected set; } public virtual string EntityId { get; set; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs new file mode 100644 index 0000000000..6eb2521ba2 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; +using Volo.CmsKit.Contents; + +namespace Volo.CmsKit.Domain.Volo.CmsKit.Contents +{ + public class ContentManager : DomainService, IContentManager + { + protected IContentRepository ContentRepository { get; } + + public ContentManager(IContentRepository contentRepository) + { + ContentRepository = contentRepository; + } + + public async Task InsertAsync(Content content, CancellationToken cancellationToken = default) + { + if (await ContentRepository.ExistsAsync(content.EntityType, content.EntityId, content.TenantId, cancellationToken)) + { + throw new ContentAlreadyExistException(content.EntityType, content.EntityId); + } + + return await ContentRepository.InsertAsync(content); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs new file mode 100644 index 0000000000..e795e7895c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs @@ -0,0 +1,11 @@ +using System.Threading; +using System.Threading.Tasks; +using Volo.CmsKit.Contents; + +namespace Volo.CmsKit.Domain.Volo.CmsKit.Contents +{ + public interface IContentManager + { + Task InsertAsync(Content content, CancellationToken cancellationToken = default); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs index acd5ed2a84..3b767b4722 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs @@ -20,6 +20,16 @@ namespace Volo.CmsKit.Contents Guid? tenantId = null, CancellationToken cancellationToken = default); - Task DeleteAsync([NotNull] string entityType, [NotNull] string entityId, Guid? tenantId = null, CancellationToken cancellationToken = default); + Task DeleteAsync( + [NotNull] string entityType, + [NotNull] string entityId, + Guid? tenantId = null, + CancellationToken cancellationToken = default); + + Task ExistsAsync( + [NotNull] string entityType, + [NotNull] string entityId, + Guid? tenantId = null, + CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/TagAlreadyExistException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/TagAlreadyExistException.cs new file mode 100644 index 0000000000..8ea4d4c54a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/TagAlreadyExistException.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using System; +using Volo.Abp; + +namespace Volo.CmsKit.Contents +{ + [Serializable] + public class ContentAlreadyExistException : BusinessException + { + public ContentAlreadyExistException([NotNull] string entityType, [NotNull] string entityId) + { + Code = CmsKitErrorCodes.ContentAlreadyExist; + WithData(nameof(Content.EntityType), entityType); + WithData(nameof(Content.EntityId), entityId); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs index 9293d637f7..884c5e9b01 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs @@ -1,4 +1,6 @@ -using System; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using System; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -20,7 +22,6 @@ namespace Volo.CmsKit.Contents CancellationToken cancellationToken = default) { return GetAsync(x => - !x.IsDeleted && x.EntityType == entityType && x.EntityId == entityId && x.TenantId == tenantId, @@ -35,7 +36,6 @@ namespace Volo.CmsKit.Contents CancellationToken cancellationToken = default) { return FindAsync(x => - !x.IsDeleted && x.EntityType == entityType && x.EntityId == entityId && x.TenantId == tenantId, @@ -43,7 +43,11 @@ namespace Volo.CmsKit.Contents ); } - public Task DeleteAsync(string entityType, string entityId, Guid? tenantId = null, CancellationToken cancellationToken = default) + public Task DeleteAsync( + string entityType, + string entityId, + Guid? tenantId = null, + CancellationToken cancellationToken = default) { return DeleteAsync(x => x.EntityType == entityType && @@ -51,5 +55,19 @@ namespace Volo.CmsKit.Contents x.TenantId == tenantId, cancellationToken: GetCancellationToken(cancellationToken)); } + + public async Task ExistsAsync( + [NotNull] string entityType, + [NotNull] string entityId, + Guid? tenantId = null, + CancellationToken cancellationToken = default) + { + var dbSet = await GetDbSetAsync(); + return await dbSet.AnyAsync(x => + x.EntityType == entityType && + x.EntityId == entityId && + x.TenantId == tenantId, + cancellationToken: GetCancellationToken(cancellationToken)); + } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs index 8e3b7160db..2cc5e8a52a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs @@ -58,8 +58,8 @@ namespace Volo.CmsKit.EntityFrameworkCore b.Property(x => x.EntityId).IsRequired().HasMaxLength(UserReactionConsts.MaxEntityIdLength); b.Property(x => x.ReactionName).IsRequired().HasMaxLength(UserReactionConsts.MaxReactionNameLength); - b.HasIndex(x => new { x.TenantId, x.EntityType, x.EntityId, x.ReactionName }); - b.HasIndex(x => new { x.TenantId, x.CreatorId, x.EntityType, x.EntityId, x.ReactionName }); + b.HasIndex(x => new {x.TenantId, x.EntityType, x.EntityId, x.ReactionName}); + b.HasIndex(x => new {x.TenantId, x.CreatorId, x.EntityType, x.EntityId, x.ReactionName}); }); } @@ -76,8 +76,8 @@ namespace Volo.CmsKit.EntityFrameworkCore b.Property(x => x.Text).IsRequired().HasMaxLength(CommentConsts.MaxTextLength); b.Property(x => x.RepliedCommentId); - b.HasIndex(x => new { x.TenantId, x.EntityType, x.EntityId }); - b.HasIndex(x => new { x.TenantId, x.RepliedCommentId }); + b.HasIndex(x => new {x.TenantId, x.EntityType, x.EntityId}); + b.HasIndex(x => new {x.TenantId, x.RepliedCommentId}); }); } @@ -161,6 +161,51 @@ namespace Volo.CmsKit.EntityFrameworkCore b.HasIndex(x => new { x.TenantId, x.Url }); }); } + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "Tags", options.Schema); + + b.ConfigureByConvention(); + + b.Property(x => x.EntityType).IsRequired().HasMaxLength(TagConsts.MaxEntityTypeLength); + b.Property(x => x.Name).IsRequired().HasMaxLength(TagConsts.MaxNameLength); + + b.HasIndex(x => new {x.TenantId, x.Name}); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "EntityTags", options.Schema); + + b.ConfigureByConvention(); + + b.HasKey(x => new {x.EntityId, x.TagId}); + + b.Property(x => x.EntityId).IsRequired(); + b.Property(x => x.TagId).IsRequired(); + + b.HasIndex(x => new {x.TenantId, x.EntityId, x.TagId}); + }); + } + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "Pages", options.Schema); + + b.ConfigureByConvention(); + + b.Property(x => x.Title).IsRequired().HasMaxLength(PageConsts.MaxTitleLength); + b.Property(x => x.Url).IsRequired().HasMaxLength(PageConsts.MaxUrlLength); + b.Property(x => x.Description).HasMaxLength(PageConsts.MaxDescriptionLength); + + b.HasIndex(x => new {x.TenantId, x.Url}); + }); + } } } -} +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs index ccdee8b431..f42b0890e7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs @@ -1,4 +1,6 @@ -using System; +using JetBrains.Annotations; +using MongoDB.Driver.Linq; +using System; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; @@ -20,7 +22,6 @@ namespace Volo.CmsKit.MongoDB.Contents CancellationToken cancellationToken = default) { return GetAsync(x => - !x.IsDeleted && x.EntityType == entityType && x.EntityId == entityId && x.TenantId == tenantId, @@ -35,7 +36,6 @@ namespace Volo.CmsKit.MongoDB.Contents CancellationToken cancellationToken = default) { return FindAsync(x => - !x.IsDeleted && x.EntityType == entityType && x.EntityId == entityId && x.TenantId == tenantId, @@ -51,5 +51,14 @@ namespace Volo.CmsKit.MongoDB.Contents x.TenantId == tenantId, cancellationToken: GetCancellationToken(cancellationToken)); } + + public async Task ExistsAsync([NotNull] string entityType, [NotNull] string entityId, Guid? tenantId = null, CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync()).AnyAsync(x => + x.EntityType == entityType && + x.EntityId == entityId && + x.TenantId == tenantId, + cancellationToken: GetCancellationToken(cancellationToken)); + } } } \ No newline at end of file diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs new file mode 100644 index 0000000000..d8c5d62a61 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs @@ -0,0 +1,129 @@ +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Users; +using Volo.CmsKit.Admin.Contents; +using Xunit; + +namespace Volo.CmsKit.Contents +{ + public class ContentAdminAppService_Tests : CmsKitApplicationTestBase + { + private ICurrentUser _currentUser; + private readonly CmsKitTestData _data; + private readonly IContentAdminAppService _service; + public ContentAdminAppService_Tests() + { + _data = GetRequiredService(); + _service = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + _currentUser = Substitute.For(); + services.AddSingleton(_currentUser); + } + + [Fact] + public async Task ShouldGetListAsync() + { + var result = await _service.GetListAsync(new ContentGetListInput()); + + result.ShouldNotBeNull(); + result.Items.ShouldNotBeEmpty(); + result.Items.Count.ShouldBe(4); + } + + [Fact] + public async Task ShouldGetAsync() + { + var result = await _service.GetAsync(_data.Content_1_Id); + + result.ShouldNotBeNull(); + } + + [Fact] + public async Task ShouldCreateAsync() + { + var entityId = "1-2-3"; + var entityType = "My.Awesome.Blog"; + var value = "Some long content"; + + var created = await _service.CreateAsync(new ContentCreateDto + { + EntityId = entityId, + EntityType = entityType, + Value = value + }); + + created.Id.ShouldNotBe(Guid.Empty); + + var content = await _service.GetAsync(created.Id); + + content.ShouldNotBeNull(); + content.EntityType.ShouldBe(entityType); + } + + [Fact] + public async Task ShouldNotCreateWithSameParametersAsync() + { + var entityTtype = "My.Awesome.Book"; + var entityId = "1"; + + await _service.CreateAsync(new ContentCreateDto + { + EntityId = entityId, + EntityType = entityTtype, + Value = "Some long content" + }); + + await Should.ThrowAsync(async () => + await _service.CreateAsync(new ContentCreateDto + { + EntityId = entityId, + EntityType = entityTtype, + Value = "Yet another long content" + }) + ); + } + + [Fact] + public async Task ShouldUpdateAsync() + { + string newValue = "Newly created fresh value"; + var updateDto = new ContentUpdateDto + { + Value = newValue + }; + + await _service.UpdateAsync(_data.Content_1_Id, updateDto); + + var content = await _service.GetAsync(_data.Content_1_Id); + content.ShouldNotBeNull(); + content.Value.ShouldBe(newValue); + } + + [Fact] + public async Task ShouldDeleteAsync() + { + await _service.DeleteAsync(_data.Content_2_Id); + + await Should.ThrowAsync(async () => await _service.GetAsync(_data.Content_2_Id)); + } + + [Fact] + public async Task ShouldNotThrowEntityNotFoundExceptionWhileDeletingAlreadyDeletedAsync() + { + await _service.DeleteAsync(_data.Content_2_Id); + + await Should.NotThrowAsync(async () => + await _service.DeleteAsync(_data.Content_2_Id)); + } + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs index b0f820a4f2..46a552641b 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; @@ -202,21 +203,32 @@ namespace Volo.CmsKit private async Task SeedContentsAsync() { var content1 = new Content( - _guidGenerator.Create(), - _cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_Id, + _cmsKitTestData.Content_1_EntityType, + _cmsKitTestData.Content_1_EntityId, _cmsKitTestData.Content_1 ); var content2 = new Content( - _guidGenerator.Create(), - _cmsKitTestData.Content_2_EntityType, _cmsKitTestData.Content_2_Id, + _cmsKitTestData.Content_2_EntityType, + _cmsKitTestData.Content_2_EntityId, _cmsKitTestData.Content_2 ); + + var content3 = new Content( + Guid.NewGuid(), + "deleted_entity_type", + "deleted_entity_id", + "Content" + ) + { + IsDeleted = true, + }; await _contentRepository.InsertAsync(content1); await _contentRepository.InsertAsync(content2); + await _contentRepository.InsertAsync(content3); } private async Task SeedTagsAsync() @@ -225,14 +237,14 @@ namespace Volo.CmsKit { var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_1_EntityType, tag); - await _entityTagRepository.InsertAsync(new EntityTag(tagEntity.Id, _cmsKitTestData.Content_1_Id)); + await _entityTagRepository.InsertAsync(new EntityTag(tagEntity.Id, _cmsKitTestData.Content_1_EntityId)); } foreach (var tag in _cmsKitTestData.Content_2_Tags) { var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_2_EntityType, tag); - await _entityTagRepository.InsertAsync(new EntityTag(tagEntity.Id, _cmsKitTestData.Content_2_Id)); + await _entityTagRepository.InsertAsync(new EntityTag(tagEntity.Id, _cmsKitTestData.Content_2_EntityId)); } } diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs index 11aa185ddd..7433759f40 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs @@ -21,39 +21,43 @@ namespace Volo.CmsKit public string EntityId2 { get; } = "2"; public string Content_1_EntityType { get; } = "Lyrics"; - + public string Content_1 { get; } = "First things first\nI'ma say all the words inside my head\nI'm fired up and tired of the way that things have been, oh-ooh\nThe way that things have been, oh-ooh"; - public string Content_1_Id { get; } = "1"; + public Guid Content_1_Id { get; } = Guid.NewGuid(); + + public string Content_1_EntityId { get; } = "1"; + + public string[] Content_1_Tags => new string[] { "Imagine Dragons", "Music" }; - public string[] Content_1_Tags => new string[] {"Imagine Dragons", "Music"}; - public string Content_2_EntityType { get; } = "LyricsAlso"; - + public string Content_2 { get; } = "Second thing second\nDon't you tell me what you think that I could be\nI'm the one at the sail, I'm the master of my sea, oh-ooh\nThe master of my sea, oh-ooh"; - - public string Content_2_Id { get; } = "2"; - - public string[] Content_2_Tags => new string[] {"Imagine Dragons", "Music", "Most Loved Part"}; + + public Guid Content_2_Id { get; } = Guid.NewGuid(); + + public string Content_2_EntityId { get; } = "2"; + + public string[] Content_2_Tags => new string[] { "Imagine Dragons", "Music", "Most Loved Part" }; public string Page_1_Title { get; } = "Imagine Dragons - Believer Lyrics"; public string Page_1_Url { get; } = "imagine-dragons-believer-lyrics"; - + public string Page_1_Description { get; } = "You can get the lyrics of the music."; - + public Guid Page_1_Id { get; } = Guid.NewGuid(); public string Page_1_Content => Content_1; - + public string Page_2_Title { get; } = "Imagine Dragons - Believer Lyrics (Page 2)"; public string Page_2_Url { get; } = "imagine-dragons-believer-lyrics-2"; - + public string Page_2_Description { get; } = "You can get the lyrics of the music."; - + public Guid Page_2_Id { get; } = Guid.NewGuid(); - + public string Page_2_Content => Content_2; } } diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs index c92383694e..c5b166551e 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs @@ -47,7 +47,7 @@ namespace Volo.CmsKit.Contents public async Task ShouldFindAsync() { var content = - await _contentRepository.FindAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_Id); + await _contentRepository.FindAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); content.ShouldNotBeNull(); }