diff --git a/api/src/Kurs.Platform.Application.Contracts/Blog/BlogCategoryDto.cs b/api/src/Kurs.Platform.Application.Contracts/Blog/BlogCategoryDto.cs index 367cd6dd..7b950369 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Blog/BlogCategoryDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Blog/BlogCategoryDto.cs @@ -5,6 +5,7 @@ namespace Kurs.Platform.Blog { public class BlogCategoryDto : FullAuditedEntityDto { + public Guid? TenantId { get; set; } public string Name { get; set; } public string Slug { get; set; } public string Description { get; set; } @@ -16,6 +17,7 @@ namespace Kurs.Platform.Blog public class CreateUpdateBlogCategoryDto { + public Guid? TenantId { get; set; } public string Name { get; set; } public string Slug { get; set; } public string Description { get; set; } diff --git a/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs b/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs index ce47fdcb..5751f332 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs @@ -6,6 +6,7 @@ namespace Kurs.Platform.Blog { public class BlogPostDto : FullAuditedEntityDto { + public Guid? TenantId { get; set; } public string Title { get; set; } public string Slug { get; set; } public string ContentTr { get; set; } @@ -30,7 +31,7 @@ namespace Kurs.Platform.Blog public BlogPostDto() { - Tags = new List(); + Tags = []; } } @@ -43,6 +44,7 @@ namespace Kurs.Platform.Blog public class CreateUpdateBlogPostDto { + public Guid? TenantId { get; set; } public string Title { get; set; } public string Slug { get; set; } public string ContentTr { get; set; } @@ -56,12 +58,13 @@ namespace Kurs.Platform.Blog public CreateUpdateBlogPostDto() { - Tags = new List(); + Tags = []; } } public class BlogPostListDto : EntityDto { + public Guid? TenantId { get; set; } public string Title { get; set; } public string Slug { get; set; } public string Summary { get; set; } @@ -85,7 +88,7 @@ namespace Kurs.Platform.Blog public BlogPostListDto() { - Tags = new List(); + Tags = []; } } } diff --git a/api/src/Kurs.Platform.Application.Contracts/Forum/ForumDtos.cs b/api/src/Kurs.Platform.Application.Contracts/Forum/ForumDtos.cs index bee65b7f..95862169 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Forum/ForumDtos.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Forum/ForumDtos.cs @@ -28,8 +28,9 @@ public class ForumSearchResultDto } // Category DTOs -public class ForumCategoryDto : EntityDto +public class ForumCategoryDto : FullAuditedEntityDto { + public Guid? TenantId { get; set; } public string Name { get; set; } public string Slug { get; set; } public string Description { get; set; } @@ -45,6 +46,8 @@ public class ForumCategoryDto : EntityDto public class CreateForumCategoryDto { + public Guid? TenantId { get; set; } + [Required] [StringLength(100)] public string Name { get; set; } @@ -82,8 +85,9 @@ public class GetCategoriesInput : PagedAndSortedResultRequestDto } // Topic DTOs -public class ForumTopicDto : EntityDto +public class ForumTopicDto : FullAuditedEntityDto { + public Guid? TenantId { get; set; } public string Title { get; set; } public string Content { get; set; } public Guid CategoryId { get; set; } @@ -103,6 +107,8 @@ public class ForumTopicDto : EntityDto public class CreateForumTopicDto { + public Guid? TenantId { get; set; } + [Required] [StringLength(200)] public string Title { get; set; } @@ -119,6 +125,8 @@ public class CreateForumTopicDto public class UpdateForumTopicDto { + public Guid? TenantId { get; set; } + [Required] [StringLength(200)] public string Title { get; set; } @@ -140,8 +148,9 @@ public class GetTopicsInput : PagedAndSortedResultRequestDto } // Post DTOs -public class ForumPostDto : EntityDto +public class ForumPostDto : FullAuditedEntityDto { + public Guid? TenantId { get; set; } public Guid TopicId { get; set; } public string Content { get; set; } public Guid AuthorId { get; set; } @@ -154,6 +163,8 @@ public class ForumPostDto : EntityDto public class CreateForumPostDto { + public Guid? TenantId { get; set; } + [Required] public Guid TopicId { get; set; } @@ -165,6 +176,8 @@ public class CreateForumPostDto public class UpdateForumPostDto { + public Guid? TenantId { get; set; } + [Required] public string Content { get; set; } diff --git a/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs b/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs index 897ae21e..26383428 100644 --- a/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs +++ b/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Kurs.Platform.Entities; using Kurs.Platform.Localization; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Localization; @@ -149,7 +150,7 @@ namespace Kurs.Platform.Blog { var post = await _postRepository.GetAsync(id); - if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.Blog.Update")) + if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.BlogManagement.Update")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } @@ -186,7 +187,7 @@ namespace Kurs.Platform.Blog var post = await _postRepository.GetAsync(id); // Check if user is author or has permission - if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.Blog.Delete")) + if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.BlogManagement.Delete")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } @@ -204,7 +205,7 @@ namespace Kurs.Platform.Blog var post = await _postRepository.GetAsync(id); // Check if user is author or has permission - if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.Blog.Publish")) + if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.BlogManagement.Publish")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } @@ -220,7 +221,7 @@ namespace Kurs.Platform.Blog var post = await _postRepository.GetAsync(id); // Check if user is author or has permission - if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.Blog.Publish")) + if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.BlogManagement.Publish")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } @@ -262,7 +263,7 @@ namespace Kurs.Platform.Blog return ObjectMapper.Map(category); } - [Authorize("App.Blog.Create")] + [Authorize("App.BlogManagement.Create")] public async Task CreateCategoryAsync(CreateUpdateBlogCategoryDto input) { var category = new BlogCategory( @@ -282,7 +283,7 @@ namespace Kurs.Platform.Blog return ObjectMapper.Map(category); } - [Authorize("App.Blog.Update")] + [Authorize("App.BlogManagement.Update")] public async Task UpdateCategoryAsync(Guid id, CreateUpdateBlogCategoryDto input) { var category = await _categoryRepository.GetAsync(id); @@ -299,7 +300,7 @@ namespace Kurs.Platform.Blog return ObjectMapper.Map(category); } - [Authorize("App.Blog.Delete")] + [Authorize("App.BlogManagement.Delete")] public async Task DeleteCategoryAsync(Guid id) { // Check if category has posts diff --git a/api/src/Kurs.Platform.Application/Blog/BlogAutoMapperProfile.cs b/api/src/Kurs.Platform.Application/Blog/BlogAutoMapperProfile.cs index 45f8a95a..dcdc6c5f 100644 --- a/api/src/Kurs.Platform.Application/Blog/BlogAutoMapperProfile.cs +++ b/api/src/Kurs.Platform.Application/Blog/BlogAutoMapperProfile.cs @@ -1,5 +1,6 @@ using AutoMapper; using Kurs.Platform.Blog; +using Kurs.Platform.Entities; namespace Kurs.Platform; diff --git a/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs b/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs index 9de3c5ae..8e6159e6 100644 --- a/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs +++ b/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Dtos; using Volo.Abp.Authorization; using Volo.Abp.Domain.Entities; @@ -186,6 +187,24 @@ public class ForumAppService : PlatformAppService, IForumAppService return ObjectMapper.Map(category); } + [Authorize("App.ForumManagement.Update")] + public async Task UpdateCategoryLockAsync(Guid id) + { + var category = await _categoryRepository.GetAsync(id); + category.IsLocked = !category.IsLocked; + await _categoryRepository.UpdateAsync(category); + return ObjectMapper.Map(category); + } + + [Authorize("App.ForumManagement.Update")] + public async Task UpdateCategoryActiveAsync(Guid id) + { + var category = await _categoryRepository.GetAsync(id); + category.IsActive = !category.IsActive; + await _categoryRepository.UpdateAsync(category); + return ObjectMapper.Map(category); + } + [Authorize("App.ForumManagement.Delete")] public async Task DeleteCategoryAsync(Guid id) { diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogCategory.cs b/api/src/Kurs.Platform.Domain/Blog/BlogCategory.cs deleted file mode 100644 index 7b6bc792..00000000 --- a/api/src/Kurs.Platform.Domain/Blog/BlogCategory.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Kurs.Platform.Blog -{ - public class BlogCategory : FullAuditedEntity, IMultiTenant - { - public Guid? TenantId { get; set; } - - public string Name { get; set; } - public string Slug { get; set; } - public string Description { get; set; } - public string Icon { get; set; } - public int DisplayOrder { get; set; } - public bool IsActive { get; set; } - public int PostCount { get; set; } - - public virtual ICollection Posts { get; set; } - - protected BlogCategory() - { - Posts = new HashSet(); - } - - public BlogCategory( - Guid id, - string name, - string slug, - string description = null, - Guid? tenantId = null) : base(id) - { - Name = name; - Slug = slug; - Description = description; - TenantId = tenantId; - Icon = null; - DisplayOrder = 0; - IsActive = true; - PostCount = 0; - Posts = new HashSet(); - } - - public void IncrementPostCount() - { - PostCount++; - } - - public void DecrementPostCount() - { - if (PostCount > 0) - PostCount--; - } - } -} diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs b/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs deleted file mode 100644 index ec75d6b5..00000000 --- a/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Kurs.Platform.Blog -{ - public class BlogPost : FullAuditedAggregateRoot, IMultiTenant - { - public Guid? TenantId { get; set; } - - public string Title { get; set; } - public string Slug { get; set; } - public string ContentTr { get; set; } - public string ContentEn { get; set; } - public string Summary { get; set; } - public string CoverImage { get; set; } - public string ReadTime { get; set; } - - public Guid CategoryId { get; set; } - public virtual BlogCategory Category { get; set; } - - public Guid AuthorId { get; set; } - - public int ViewCount { get; set; } - public int LikeCount { get; set; } - public int CommentCount { get; set; } - - public bool IsPublished { get; set; } - public DateTime? PublishedAt { get; set; } - - protected BlogPost() - { - } - - public BlogPost( - Guid id, - string title, - string slug, - string contentTr, - string contentEn, - string summary, - string readTime, - string coverImage, - Guid categoryId, - Guid authorId, - Guid? tenantId = null) : base(id) - { - Title = title; - Slug = slug; - ContentTr = contentTr; - ContentEn = contentEn; - Summary = summary; - ReadTime = readTime; - CoverImage = coverImage; - CategoryId = categoryId; - AuthorId = authorId; - TenantId = tenantId; - - ViewCount = 0; - LikeCount = 0; - CommentCount = 0; - IsPublished = false; - } - - public void Publish() - { - IsPublished = true; - PublishedAt = DateTime.UtcNow; - } - - public void Unpublish() - { - IsPublished = false; - PublishedAt = null; - } - } -} diff --git a/api/src/Kurs.Platform.Domain/Entities/BlogCategory.cs b/api/src/Kurs.Platform.Domain/Entities/BlogCategory.cs new file mode 100644 index 00000000..86a48c5a --- /dev/null +++ b/api/src/Kurs.Platform.Domain/Entities/BlogCategory.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Kurs.Platform.Entities; + +public class BlogCategory : FullAuditedEntity +{ + public Guid? TenantId { get; set; } + public string Name { get; set; } + public string Slug { get; set; } + public string Description { get; set; } + public string Icon { get; set; } + public int DisplayOrder { get; set; } + public bool IsActive { get; set; } + public int PostCount { get; set; } + + public virtual ICollection Posts { get; set; } + + protected BlogCategory() + { + Posts = new HashSet(); + } + + public BlogCategory( + Guid id, + string name, + string slug, + string description = null, + Guid? tenantId = null) : base(id) + { + Name = name; + Slug = slug; + Description = description; + TenantId = tenantId; + Icon = null; + DisplayOrder = 0; + IsActive = true; + PostCount = 0; + Posts = new HashSet(); + } + + public void IncrementPostCount() + { + PostCount++; + } + + public void DecrementPostCount() + { + if (PostCount > 0) + PostCount--; + } +} diff --git a/api/src/Kurs.Platform.Domain/Entities/BlogPost.cs b/api/src/Kurs.Platform.Domain/Entities/BlogPost.cs new file mode 100644 index 00000000..7ded6478 --- /dev/null +++ b/api/src/Kurs.Platform.Domain/Entities/BlogPost.cs @@ -0,0 +1,75 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Kurs.Platform.Entities; + +public class BlogPost : FullAuditedAggregateRoot +{ + public Guid? TenantId { get; set; } + public string Title { get; set; } + public string Slug { get; set; } + public string ContentTr { get; set; } + public string ContentEn { get; set; } + public string Summary { get; set; } + public string CoverImage { get; set; } + public string ReadTime { get; set; } + + public Guid CategoryId { get; set; } + public virtual BlogCategory Category { get; set; } + + public Guid AuthorId { get; set; } + + public int ViewCount { get; set; } + public int LikeCount { get; set; } + public int CommentCount { get; set; } + + public bool IsPublished { get; set; } + public DateTime? PublishedAt { get; set; } + + protected BlogPost() + { + } + + public BlogPost( + Guid id, + string title, + string slug, + string contentTr, + string contentEn, + string summary, + string readTime, + string coverImage, + Guid categoryId, + Guid authorId, + Guid? tenantId = null) : base(id) + { + Title = title; + Slug = slug; + ContentTr = contentTr; + ContentEn = contentEn; + Summary = summary; + ReadTime = readTime; + CoverImage = coverImage; + CategoryId = categoryId; + AuthorId = authorId; + TenantId = tenantId; + + ViewCount = 0; + LikeCount = 0; + CommentCount = 0; + IsPublished = false; + } + + public void Publish() + { + IsPublished = true; + PublishedAt = DateTime.UtcNow; + } + + public void Unpublish() + { + IsPublished = false; + PublishedAt = null; + } +} diff --git a/api/src/Kurs.Platform.Domain/Entities/Forum.cs b/api/src/Kurs.Platform.Domain/Entities/Forum.cs deleted file mode 100644 index 82130865..00000000 --- a/api/src/Kurs.Platform.Domain/Entities/Forum.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using Volo.Abp.Domain.Entities.Auditing; - -namespace Kurs.Platform.Forum; - -public class ForumCategory : FullAuditedEntity -{ - public string Name { get; set; } - public string Slug { get; set; } - public string Description { get; set; } - public string Icon { get; set; } - public int DisplayOrder { get; set; } - public bool IsActive { get; set; } - public bool IsLocked { get; set; } - public int TopicCount { get; set; } - public int PostCount { get; set; } - public Guid? LastPostId { get; set; } - public DateTime? LastPostDate { get; set; } - public Guid? LastPostUserId { get; set; } - public string LastPostUserName { get; set; } - - public ICollection Topics { get; set; } - - protected ForumCategory() { } - - public ForumCategory(Guid id, string name, string slug, string description, string icon, int displayOrder) : base(id) - { - Name = name; - Slug = slug; - Description = description; - Icon = icon; - DisplayOrder = displayOrder; - IsActive = true; - IsLocked = false; - TopicCount = 0; - PostCount = 0; - Topics = []; - } -} - -public class ForumTopic : FullAuditedEntity -{ - public string Title { get; set; } - public string Content { get; set; } - public Guid CategoryId { get; set; } - public Guid AuthorId { get; set; } - public string AuthorName { get; set; } - public int ViewCount { get; set; } - public int ReplyCount { get; set; } - public int LikeCount { get; set; } - public bool IsPinned { get; set; } - public bool IsLocked { get; set; } - public bool IsSolved { get; set; } - public Guid? LastPostId { get; set; } - public DateTime? LastPostDate { get; set; } - public Guid? LastPostUserId { get; set; } - public string LastPostUserName { get; set; } - - public ForumCategory Category { get; set; } - public ICollection Posts { get; set; } - - protected ForumTopic() { } - - public ForumTopic(Guid id, string title, string content, Guid categoryId, Guid authorId, string authorName) : base(id) - { - Title = title; - Content = content; - CategoryId = categoryId; - AuthorId = authorId; - AuthorName = authorName; - ViewCount = 0; - ReplyCount = 0; - LikeCount = 0; - IsPinned = false; - IsLocked = false; - IsSolved = false; - Posts = []; - } -} - -public class ForumPost : FullAuditedEntity -{ - public Guid TopicId { get; set; } - public string Content { get; set; } - public Guid AuthorId { get; set; } - public string AuthorName { get; set; } - public int LikeCount { get; set; } - public bool IsAcceptedAnswer { get; set; } - public Guid? ParentPostId { get; set; } - - public ForumTopic Topic { get; set; } - public ForumPost ParentPost { get; set; } - public ICollection Replies { get; set; } - - protected ForumPost() { } - - public ForumPost(Guid id, Guid topicId, string content, Guid authorId, string authorName, Guid? parentPostId = null) : base(id) - { - TopicId = topicId; - Content = content; - AuthorId = authorId; - AuthorName = authorName; - ParentPostId = parentPostId; - LikeCount = 0; - IsAcceptedAnswer = false; - Replies = []; - } -} \ No newline at end of file diff --git a/api/src/Kurs.Platform.Domain/Entities/ForumCategory.cs b/api/src/Kurs.Platform.Domain/Entities/ForumCategory.cs new file mode 100644 index 00000000..4d3dcc74 --- /dev/null +++ b/api/src/Kurs.Platform.Domain/Entities/ForumCategory.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Kurs.Platform.Forum; + +public class ForumCategory : FullAuditedEntity +{ + public string Name { get; set; } + public string Slug { get; set; } + public string Description { get; set; } + public string Icon { get; set; } + public int DisplayOrder { get; set; } + public bool IsActive { get; set; } + public bool IsLocked { get; set; } + public int TopicCount { get; set; } + public int PostCount { get; set; } + public Guid? LastPostId { get; set; } + public DateTime? LastPostDate { get; set; } + public Guid? LastPostUserId { get; set; } + public string LastPostUserName { get; set; } + + public ICollection Topics { get; set; } + + public Guid? TenantId { get; set; } + + protected ForumCategory() { } + + public ForumCategory(Guid id, string name, string slug, string description, string icon, int displayOrder, Guid? tenantId = null) : base(id) + { + Name = name; + Slug = slug; + Description = description; + Icon = icon; + DisplayOrder = displayOrder; + IsActive = true; + IsLocked = false; + TopicCount = 0; + PostCount = 0; + TenantId = tenantId; + Topics = []; + } +} diff --git a/api/src/Kurs.Platform.Domain/Entities/ForumPost.cs b/api/src/Kurs.Platform.Domain/Entities/ForumPost.cs new file mode 100644 index 00000000..c0c58e95 --- /dev/null +++ b/api/src/Kurs.Platform.Domain/Entities/ForumPost.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Kurs.Platform.Forum; + +public class ForumPost : FullAuditedEntity +{ + public Guid TopicId { get; set; } + public string Content { get; set; } + public Guid AuthorId { get; set; } + public string AuthorName { get; set; } + public int LikeCount { get; set; } + public bool IsAcceptedAnswer { get; set; } + public Guid? ParentPostId { get; set; } + public Guid? TenantId { get; set; } + + public ForumTopic Topic { get; set; } + public ForumPost ParentPost { get; set; } + public ICollection Replies { get; set; } + + protected ForumPost() { } + + public ForumPost(Guid id, Guid topicId, string content, Guid authorId, string authorName, Guid? parentPostId = null, Guid? tenantId = null) : base(id) + { + TopicId = topicId; + Content = content; + AuthorId = authorId; + AuthorName = authorName; + ParentPostId = parentPostId; + LikeCount = 0; + IsAcceptedAnswer = false; + TenantId = tenantId; + Replies = []; + } +} \ No newline at end of file diff --git a/api/src/Kurs.Platform.Domain/Entities/ForumTopic.cs b/api/src/Kurs.Platform.Domain/Entities/ForumTopic.cs new file mode 100644 index 00000000..730944ba --- /dev/null +++ b/api/src/Kurs.Platform.Domain/Entities/ForumTopic.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Kurs.Platform.Forum; + +public class ForumTopic : FullAuditedEntity +{ + public string Title { get; set; } + public string Content { get; set; } + public Guid CategoryId { get; set; } + public Guid AuthorId { get; set; } + public string AuthorName { get; set; } + public int ViewCount { get; set; } + public int ReplyCount { get; set; } + public int LikeCount { get; set; } + public bool IsPinned { get; set; } + public bool IsLocked { get; set; } + public bool IsSolved { get; set; } + public Guid? LastPostId { get; set; } + public DateTime? LastPostDate { get; set; } + public Guid? LastPostUserId { get; set; } + public string LastPostUserName { get; set; } + public Guid? TenantId { get; set; } + + public ForumCategory Category { get; set; } + public ICollection Posts { get; set; } + + protected ForumTopic() { } + + public ForumTopic(Guid id, string title, string content, Guid categoryId, Guid authorId, string authorName, Guid? tenantId = null) : base(id) + { + Title = title; + Content = content; + CategoryId = categoryId; + AuthorId = authorId; + AuthorName = authorName; + ViewCount = 0; + ReplyCount = 0; + LikeCount = 0; + IsPinned = false; + IsLocked = false; + IsSolved = false; + TenantId = tenantId; + Posts = []; + } +} \ No newline at end of file diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 34d2013c..6b65e5e6 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -1,6 +1,5 @@ using Kurs.Languages.EntityFrameworkCore; using Kurs.Platform.Entities; -using Kurs.Platform.Blog; using Kurs.Settings.EntityFrameworkCore; using Kurs.MailQueue.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623140407_AddForum.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623190205_AddForum.Designer.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623140407_AddForum.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623190205_AddForum.Designer.cs index cd64df84..ce7634c9 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623140407_AddForum.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623190205_AddForum.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20250623140407_AddForum")] + [Migration("20250623190205_AddForum")] partial class AddForum { /// @@ -653,193 +653,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PNotificationRule", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogCategory", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("DeleterId") - .HasColumnType("uniqueidentifier") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("datetime2") - .HasColumnName("DeletionTime"); - - b.Property("Description") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)"); - - b.Property("DisplayOrder") - .HasColumnType("int"); - - b.Property("Icon") - .HasColumnType("nvarchar(max)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("PostCount") - .HasColumnType("int"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("Slug"); - - b.ToTable("PBlogCategories", (string)null); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("AuthorId") - .HasColumnType("uniqueidentifier"); - - b.Property("CategoryId") - .HasColumnType("uniqueidentifier"); - - b.Property("CommentCount") - .HasColumnType("int"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .IsRequired() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("ContentEn") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("ContentTr") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("CoverImage") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("DeleterId") - .HasColumnType("uniqueidentifier") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("datetime2") - .HasColumnName("DeletionTime"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("IsPublished") - .HasColumnType("bit"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - - b.Property("LikeCount") - .HasColumnType("int"); - - b.Property("PublishedAt") - .HasColumnType("datetime2"); - - b.Property("ReadTime") - .HasColumnType("nvarchar(max)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); - - b.Property("Summary") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("nvarchar(512)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); - - b.Property("ViewCount") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("CategoryId"); - - b.HasIndex("IsPublished"); - - b.HasIndex("PublishedAt"); - - b.HasIndex("Slug"); - - b.ToTable("PBlogPosts", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Entities.AiBot", b => { b.Property("Id") @@ -1071,6 +884,193 @@ namespace Kurs.Platform.Migrations b.ToTable("BankAccounts"); }); + modelBuilder.Entity("Kurs.Platform.Entities.BlogCategory", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("Icon") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("PostCount") + .HasColumnType("int"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Slug"); + + b.ToTable("PBlogCategories", (string)null); + }); + + modelBuilder.Entity("Kurs.Platform.Entities.BlogPost", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("CategoryId") + .HasColumnType("uniqueidentifier"); + + b.Property("CommentCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContentEn") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ContentTr") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CoverImage") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LikeCount") + .HasColumnType("int"); + + b.Property("PublishedAt") + .HasColumnType("datetime2"); + + b.Property("ReadTime") + .HasColumnType("nvarchar(max)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Summary") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ViewCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("IsPublished"); + + b.HasIndex("PublishedAt"); + + b.HasIndex("Slug"); + + b.ToTable("PBlogPosts", (string)null); + }); + modelBuilder.Entity("Kurs.Platform.Entities.Branch", b => { b.Property("Id") @@ -2514,6 +2514,10 @@ namespace Kurs.Platform.Migrations b.Property("Slug") .HasColumnType("nvarchar(max)"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("TopicCount") .HasColumnType("int"); @@ -2578,6 +2582,10 @@ namespace Kurs.Platform.Migrations b.Property("ParentPostId") .HasColumnType("uniqueidentifier"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("TopicId") .HasColumnType("uniqueidentifier"); @@ -2665,6 +2673,10 @@ namespace Kurs.Platform.Migrations b.Property("ReplyCount") .HasColumnType("int"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("Title") .IsRequired() .HasMaxLength(256) @@ -4757,17 +4769,6 @@ namespace Kurs.Platform.Migrations .OnDelete(DeleteBehavior.SetNull); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => - { - b.HasOne("Kurs.Platform.Blog.BlogCategory", "Category") - .WithMany("Posts") - .HasForeignKey("CategoryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Category"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.BankAccount", b => { b.HasOne("Kurs.Platform.Entities.Bank", "Bank") @@ -4785,6 +4786,17 @@ namespace Kurs.Platform.Migrations b.Navigation("Currency"); }); + modelBuilder.Entity("Kurs.Platform.Entities.BlogPost", b => + { + b.HasOne("Kurs.Platform.Entities.BlogCategory", "Category") + .WithMany("Posts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + modelBuilder.Entity("Kurs.Platform.Entities.Country", b => { b.HasOne("Kurs.Platform.Entities.CountryGroup", null) @@ -5027,7 +5039,7 @@ namespace Kurs.Platform.Migrations b.Navigation("Texts"); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogCategory", b => + modelBuilder.Entity("Kurs.Platform.Entities.BlogCategory", b => { b.Navigation("Posts"); }); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623140407_AddForum.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623190205_AddForum.cs similarity index 97% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623140407_AddForum.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623190205_AddForum.cs index 78645705..b1563afe 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623140407_AddForum.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250623190205_AddForum.cs @@ -29,6 +29,7 @@ namespace Kurs.Platform.Migrations LastPostDate = table.Column(type: "datetime2", nullable: true), LastPostUserId = table.Column(type: "uniqueidentifier", nullable: true), LastPostUserName = table.Column(type: "nvarchar(max)", nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), CreatorId = table.Column(type: "uniqueidentifier", nullable: true), LastModificationTime = table.Column(type: "datetime2", nullable: true), @@ -62,6 +63,7 @@ namespace Kurs.Platform.Migrations LastPostDate = table.Column(type: "datetime2", nullable: true), LastPostUserId = table.Column(type: "uniqueidentifier", nullable: true), LastPostUserName = table.Column(type: "nvarchar(max)", nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), CreatorId = table.Column(type: "uniqueidentifier", nullable: true), LastModificationTime = table.Column(type: "datetime2", nullable: true), @@ -93,6 +95,7 @@ namespace Kurs.Platform.Migrations LikeCount = table.Column(type: "int", nullable: false), IsAcceptedAnswer = table.Column(type: "bit", nullable: false), ParentPostId = table.Column(type: "uniqueidentifier", nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), CreatorId = table.Column(type: "uniqueidentifier", nullable: true), LastModificationTime = table.Column(type: "datetime2", nullable: true), diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index 0b9be550..be026391 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -650,193 +650,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PNotificationRule", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogCategory", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("DeleterId") - .HasColumnType("uniqueidentifier") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("datetime2") - .HasColumnName("DeletionTime"); - - b.Property("Description") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)"); - - b.Property("DisplayOrder") - .HasColumnType("int"); - - b.Property("Icon") - .HasColumnType("nvarchar(max)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("PostCount") - .HasColumnType("int"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("Slug"); - - b.ToTable("PBlogCategories", (string)null); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("AuthorId") - .HasColumnType("uniqueidentifier"); - - b.Property("CategoryId") - .HasColumnType("uniqueidentifier"); - - b.Property("CommentCount") - .HasColumnType("int"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .IsRequired() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("ContentEn") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("ContentTr") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("CoverImage") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("DeleterId") - .HasColumnType("uniqueidentifier") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("datetime2") - .HasColumnName("DeletionTime"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("IsPublished") - .HasColumnType("bit"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - - b.Property("LikeCount") - .HasColumnType("int"); - - b.Property("PublishedAt") - .HasColumnType("datetime2"); - - b.Property("ReadTime") - .HasColumnType("nvarchar(max)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); - - b.Property("Summary") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("nvarchar(512)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); - - b.Property("ViewCount") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("CategoryId"); - - b.HasIndex("IsPublished"); - - b.HasIndex("PublishedAt"); - - b.HasIndex("Slug"); - - b.ToTable("PBlogPosts", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Entities.AiBot", b => { b.Property("Id") @@ -1068,6 +881,193 @@ namespace Kurs.Platform.Migrations b.ToTable("BankAccounts"); }); + modelBuilder.Entity("Kurs.Platform.Entities.BlogCategory", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("Icon") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("PostCount") + .HasColumnType("int"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Slug"); + + b.ToTable("PBlogCategories", (string)null); + }); + + modelBuilder.Entity("Kurs.Platform.Entities.BlogPost", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("CategoryId") + .HasColumnType("uniqueidentifier"); + + b.Property("CommentCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContentEn") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ContentTr") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CoverImage") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LikeCount") + .HasColumnType("int"); + + b.Property("PublishedAt") + .HasColumnType("datetime2"); + + b.Property("ReadTime") + .HasColumnType("nvarchar(max)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Summary") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ViewCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("IsPublished"); + + b.HasIndex("PublishedAt"); + + b.HasIndex("Slug"); + + b.ToTable("PBlogPosts", (string)null); + }); + modelBuilder.Entity("Kurs.Platform.Entities.Branch", b => { b.Property("Id") @@ -2511,6 +2511,10 @@ namespace Kurs.Platform.Migrations b.Property("Slug") .HasColumnType("nvarchar(max)"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("TopicCount") .HasColumnType("int"); @@ -2575,6 +2579,10 @@ namespace Kurs.Platform.Migrations b.Property("ParentPostId") .HasColumnType("uniqueidentifier"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("TopicId") .HasColumnType("uniqueidentifier"); @@ -2662,6 +2670,10 @@ namespace Kurs.Platform.Migrations b.Property("ReplyCount") .HasColumnType("int"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("Title") .IsRequired() .HasMaxLength(256) @@ -4754,17 +4766,6 @@ namespace Kurs.Platform.Migrations .OnDelete(DeleteBehavior.SetNull); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => - { - b.HasOne("Kurs.Platform.Blog.BlogCategory", "Category") - .WithMany("Posts") - .HasForeignKey("CategoryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Category"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.BankAccount", b => { b.HasOne("Kurs.Platform.Entities.Bank", "Bank") @@ -4782,6 +4783,17 @@ namespace Kurs.Platform.Migrations b.Navigation("Currency"); }); + modelBuilder.Entity("Kurs.Platform.Entities.BlogPost", b => + { + b.HasOne("Kurs.Platform.Entities.BlogCategory", "Category") + .WithMany("Posts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + modelBuilder.Entity("Kurs.Platform.Entities.Country", b => { b.HasOne("Kurs.Platform.Entities.CountryGroup", null) @@ -5024,7 +5036,7 @@ namespace Kurs.Platform.Migrations b.Navigation("Texts"); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogCategory", b => + modelBuilder.Entity("Kurs.Platform.Entities.BlogCategory", b => { b.Navigation("Posts"); }); diff --git a/company/src/services/api/blog.service.ts b/company/src/services/api/blog.service.ts index ff3cf21f..64c8cc3b 100644 --- a/company/src/services/api/blog.service.ts +++ b/company/src/services/api/blog.service.ts @@ -39,23 +39,6 @@ export interface BlogCategory { isActive: boolean; } -export interface BlogComment { - id: string; - postId: string; - content: string; - author: { - id: string; - name: string; - avatar?: string; - }; - parentId?: string; - replies?: BlogComment[]; - likeCount: number; - isLiked?: boolean; - createdAt: string; - updatedAt: string; -} - export interface CreateBlogPostRequest { title: string; slug: string; diff --git a/ui/dev-dist/sw.js b/ui/dev-dist/sw.js index 304d71f6..71fbc8e3 100644 --- a/ui/dev-dist/sw.js +++ b/ui/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.ouca2h9ms1" + "revision": "0.mvu82hb2mqg" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/ui/src/proxy/blog/blog.ts b/ui/src/proxy/blog/blog.ts new file mode 100644 index 00000000..e90cbb2a --- /dev/null +++ b/ui/src/proxy/blog/blog.ts @@ -0,0 +1,81 @@ +export interface BlogPost { + id: string + title: string + slug: string + contentTr?: string + contentEn?: string + summary: string + coverImage?: string + author: { + id: string + name: string + avatar?: string + } + category: { + id: string + name: string + slug: string + } + tags: string[] + viewCount: number + likeCount: number + commentCount: number + isPublished: boolean + publishedAt?: string + createdAt: string + updatedAt: string + tenantId?: string +} + +export interface BlogCategory { + id: string + name: string + slug: string + description?: string + postCount: number + isActive: boolean + icon: string + displayOrder: number + tenantId?: string +} + +export interface CreateUpdateBlogPostDto { + title: string + slug: string + contentTr: string + contentEn: string + summary: string + categoryId: string + tags: string[] + coverImage?: string + isPublished: boolean + tenantId?: string +} + +export interface CreateUpdateBlogCategoryDto { + tenantId?: string + name: string + slug: string + description: string + icon?: string + displayOrder: number + isActive: boolean +} + +export interface BlogListParams { + page?: number + pageSize?: number + categoryId?: string + tag?: string + search?: string + authorId?: string + sortBy?: 'latest' | 'popular' | 'trending' +} + +export interface PaginatedResponse { + items: T[] + totalCount: number + pageNumber: number + pageSize: number + totalPages: number +} \ No newline at end of file diff --git a/ui/src/proxy/forum/forum.ts b/ui/src/proxy/forum/forum.ts index e4b34ea9..9932749c 100644 --- a/ui/src/proxy/forum/forum.ts +++ b/ui/src/proxy/forum/forum.ts @@ -10,9 +10,10 @@ export interface ForumCategory { topicCount: number; postCount: number; lastPostId?: string; - lastPostDate?: Date; + lastPostDate?: string; lastPostUserId?: string; - creationTime: Date; + creationTime: string; + tenantId?: string; } export interface ForumTopic { @@ -29,10 +30,11 @@ export interface ForumTopic { isLocked: boolean; isSolved: boolean; lastPostId?: string; - lastPostDate?: Date; + lastPostDate?: string; lastPostUserId?: string; lastPostUserName?: string; - creationTime: Date; + creationTime: string; + tenantId?: string; } export interface ForumPost { @@ -44,7 +46,8 @@ export interface ForumPost { likeCount: number; isAcceptedAnswer: boolean; parentPostId?: string; - creationTime: Date; + creationTime: string; + tenantId?: string; } export type ViewMode = 'forum' | 'admin'; \ No newline at end of file diff --git a/ui/src/services/blog.service.ts b/ui/src/services/blog.service.ts index 0727f770..6501ed0e 100644 --- a/ui/src/services/blog.service.ts +++ b/ui/src/services/blog.service.ts @@ -1,106 +1,6 @@ +import { BlogCategory, BlogListParams, BlogPost, CreateUpdateBlogCategoryDto, CreateUpdateBlogPostDto, PaginatedResponse } from '@/proxy/blog/blog'; import apiService from '@/services/api.service' -export interface BlogPost { - id: string - title: string - slug: string - contentTr?: string - contentEn?: string - summary: string - coverImage?: string - author: { - id: string - name: string - avatar?: string - } - category: { - id: string - name: string - slug: string - } - tags: string[] - viewCount: number - likeCount: number - commentCount: number - isPublished: boolean - publishedAt?: string - createdAt: string - updatedAt: string -} - -export interface BlogCategory { - id: string - name: string - slug: string - description?: string - postCount: number - isActive: boolean - icon: string - displayOrder: number -} - -export interface BlogComment { - id: string - postId: string - content: string - author: { - id: string - name: string - avatar?: string - } - parentId?: string - replies?: BlogComment[] - likeCount: number - isLiked?: boolean - createdAt: string - updatedAt: string -} - -export interface CreateUpdateBlogPostDto { - title: string - slug: string - contentTr: string - contentEn: string - summary: string - categoryId: string - tags: string[] - coverImage?: string - isPublished: boolean -} - -export interface CreateUpdateBlogCategoryDto { - name: string - slug: string - description: string - icon?: string - displayOrder: number - isActive: boolean -} - -export interface CreateCommentDto { - postId: string - content: string - parentId?: string -} - -export interface BlogListParams { - page?: number - pageSize?: number - categoryId?: string - tag?: string - search?: string - authorId?: string - sortBy?: 'latest' | 'popular' | 'trending' -} - -export interface PaginatedResponse { - items: T[] - totalCount: number - pageNumber: number - pageSize: number - totalPages: number -} - class BlogService { async getPosts(params: BlogListParams = {}): Promise> { const response = await apiService.fetchData>({ @@ -176,23 +76,6 @@ class BlogService { return response.data } - async getComments(postId: string): Promise { - const response = await apiService.fetchData({ - url: `/api/app/blog/posts/${postId}/comments`, - method: 'GET', - }) - return response.data - } - - async createComment(data: CreateCommentDto): Promise { - const response = await apiService.fetchData({ - url: '/api/app/blog/comments', - method: 'POST', - data: data as any, - }) - return response.data - } - async deleteComment(id: string): Promise { await apiService.fetchData({ url: `/api/app/blog/comments/${id}`, diff --git a/ui/src/services/forumService.ts b/ui/src/services/forumService.ts index be10df29..5ffb3dce 100644 --- a/ui/src/services/forumService.ts +++ b/ui/src/services/forumService.ts @@ -35,6 +35,7 @@ export interface CreateCategoryRequest { displayOrder: number isActive: boolean isLocked: boolean + tenantId?: string } export interface CreateTopicRequest { @@ -43,12 +44,14 @@ export interface CreateTopicRequest { categoryId: string isPinned?: boolean isLocked?: boolean + tenantId?: string } export interface CreatePostRequest { topicId: string content: string parentPostId?: string + tenantId?: string } export interface CategoryListParams { @@ -115,7 +118,7 @@ class ForumService { async createCategory(data: CreateCategoryRequest): Promise { const response = await apiService.fetchData({ - url: '/api/app/forum/categories', + url: '/api/app/forum/category', method: 'POST', data, }) @@ -124,27 +127,45 @@ class ForumService { async updateCategory(id: string, data: Partial): Promise { const response = await apiService.fetchData({ - url: `/api/app/forum/categories/${id}`, + url: `/api/app/forum/${id}/category`, method: 'PUT', data, }) return response.data } + async updateCategoryLockState(id: string): Promise { + const response = await apiService.fetchData({ + url: `/api/app/forum/${id}/category-lock`, + method: 'PUT', + }) + + return response.data + } + + async updateCategoryActiveState(id: string): Promise { + const response = await apiService.fetchData({ + url: `/api/app/forum/${id}/category-active`, + method: 'PUT', + }) + + return response.data + } + async deleteCategory(id: string): Promise { await apiService.fetchData({ - url: `/api/app/forum/categories/${id}`, + url: `/api/app/forum/${id}/category`, method: 'DELETE', }) } - async toggleCategoryStatus(id: string): Promise { - const response = await apiService.fetchData({ - url: `/api/app/forum/categories/${id}/toggle-status`, - method: 'POST', - }) - return response.data - } + // async toggleCategoryStatus(id: string): Promise { + // const response = await apiService.fetchData({ + // url: `/api/app/forum/categories/${id}/toggle-status`, + // method: 'POST', + // }) + // return response.data + // } // Topics async getTopics(params: TopicListParams = {}): Promise> { @@ -175,7 +196,7 @@ class ForumService { async updateTopic(id: string, data: Partial): Promise { const response = await apiService.fetchData({ - url: `/api/app/forum/topics/${id}`, + url: `/api/app/forum/${id}/topic`, method: 'PUT', data, }) @@ -184,7 +205,7 @@ class ForumService { async deleteTopic(id: string): Promise { await apiService.fetchData({ - url: `/api/app/forum/topics/${id}`, + url: `/api/app/forum/${id}/topic`, method: 'DELETE', }) } @@ -336,10 +357,17 @@ class ForumService { totalUsers: number activeUsers: number }> { - const response = await apiService.fetchData({ + const response = await apiService.fetchData<{ + totalCategories: number + totalTopics: number + totalPosts: number + totalUsers: number + activeUsers: number + }>({ url: '/api/app/forum/stats', method: 'GET', }) + return response.data } } diff --git a/ui/src/views/blog/BlogManagement.tsx b/ui/src/views/blog/BlogManagement.tsx index 3e57af1e..d027e760 100644 --- a/ui/src/views/blog/BlogManagement.tsx +++ b/ui/src/views/blog/BlogManagement.tsx @@ -12,10 +12,6 @@ import { HiPlus, HiPencil, HiTrash, HiEye } from 'react-icons/hi' import { useNavigate } from 'react-router-dom' import { blogService, - BlogPost, - BlogCategory, - CreateUpdateBlogPostDto, - CreateUpdateBlogCategoryDto, } from '@/services/blog.service' import { format } from 'date-fns' import { tr } from 'date-fns/locale' @@ -39,6 +35,7 @@ import { useStoreState } from '@/store/store' import TabList from '@/components/ui/Tabs/TabList' import TabNav from '@/components/ui/Tabs/TabNav' import TabContent from '@/components/ui/Tabs/TabContent' +import { BlogCategory, BlogPost, CreateUpdateBlogCategoryDto, CreateUpdateBlogPostDto } from '@/proxy/blog/blog' const validationSchema = Yup.object().shape({ title: Yup.string().required(), diff --git a/ui/src/views/forum/Management.tsx b/ui/src/views/forum/Management.tsx index 3cf56212..002ab9ed 100644 --- a/ui/src/views/forum/Management.tsx +++ b/ui/src/views/forum/Management.tsx @@ -14,6 +14,8 @@ export function Management() { error, createCategory, updateCategory, + updateCategoryLockState, + updateCategoryActiveState, deleteCategory, createTopic, updateTopic, @@ -79,6 +81,8 @@ export function Management() { loading={loading} onCreateCategory={(data) => createCategory(data).then(() => {})} onUpdateCategory={(id, data) => updateCategory(id, data).then(() => {})} + onUpdateCategoryLockState={(id) => updateCategoryLockState(id).then(() => {})} + onUpdateCategoryActiveState={(id) => updateCategoryActiveState(id).then(() => {})} onDeleteCategory={(id) => deleteCategory(id).then(() => {})} onCreateTopic={(data) => createTopic(data).then(() => {})} onUpdateTopic={(id, data) => updateTopic(id, data).then(() => {})} diff --git a/ui/src/views/forum/admin/AdminView.tsx b/ui/src/views/forum/admin/AdminView.tsx index ef965643..eec8770a 100644 --- a/ui/src/views/forum/admin/AdminView.tsx +++ b/ui/src/views/forum/admin/AdminView.tsx @@ -21,6 +21,8 @@ interface AdminViewProps { isLocked: boolean; }) => Promise; onUpdateCategory: (id: string, category: Partial) => Promise; + onUpdateCategoryLockState: (id: string) => Promise; + onUpdateCategoryActiveState: (id: string) => Promise; onDeleteCategory: (id: string) => Promise; onCreateTopic: (topic: { title: string; @@ -58,6 +60,8 @@ export function AdminView({ onCreateCategory, onUpdateCategory, onDeleteCategory, + onUpdateCategoryLockState, + onUpdateCategoryActiveState, onCreateTopic, onUpdateTopic, onDeleteTopic, @@ -121,6 +125,8 @@ export function AdminView({ onCreateCategory={onCreateCategory} onUpdateCategory={onUpdateCategory} onDeleteCategory={onDeleteCategory} + onUpdateCategoryLockState={onUpdateCategoryLockState} + onUpdateCategoryActiveState={onUpdateCategoryActiveState} /> )} diff --git a/ui/src/views/forum/admin/CategoryManagement.tsx b/ui/src/views/forum/admin/CategoryManagement.tsx index c75b420a..03d482e2 100644 --- a/ui/src/views/forum/admin/CategoryManagement.tsx +++ b/ui/src/views/forum/admin/CategoryManagement.tsx @@ -16,6 +16,8 @@ interface CategoryManagementProps { }) => Promise; onUpdateCategory: (id: string, category: Partial) => Promise; onDeleteCategory: (id: string) => Promise; + onUpdateCategoryLockState: (id: string) => Promise; + onUpdateCategoryActiveState: (id: string) => Promise; } export function CategoryManagement({ @@ -23,7 +25,9 @@ export function CategoryManagement({ loading, onCreateCategory, onUpdateCategory, - onDeleteCategory + onDeleteCategory, + onUpdateCategoryLockState, + onUpdateCategoryActiveState }: CategoryManagementProps) { const [showCreateForm, setShowCreateForm] = useState(false); const [editingCategory, setEditingCategory] = useState(null); @@ -87,7 +91,7 @@ export function CategoryManagement({ const handleToggleActive = async (category: ForumCategory) => { try { - await onUpdateCategory(category.id, { isActive: !category.isActive }); + await onUpdateCategoryActiveState(category.id); } catch (error) { console.error('Error toggling category status:', error); } @@ -95,7 +99,7 @@ export function CategoryManagement({ const handleToggleLocked = async (category: ForumCategory) => { try { - await onUpdateCategory(category.id, { isLocked: !category.isLocked }); + await onUpdateCategoryLockState(category.id); } catch (error) { console.error('Error toggling category lock:', error); } diff --git a/ui/src/views/forum/admin/PostManagement.tsx b/ui/src/views/forum/admin/PostManagement.tsx index b4191f9b..4200b9b8 100644 --- a/ui/src/views/forum/admin/PostManagement.tsx +++ b/ui/src/views/forum/admin/PostManagement.tsx @@ -1,116 +1,115 @@ -import React, { useState } from 'react'; -import { Plus, Edit2, Trash2, CheckCircle, Circle, Heart, Loader2 } from 'lucide-react'; -import { ForumPost, ForumTopic } from '@/proxy/forum/forum'; +import React, { useState } from 'react' +import { Plus, Edit2, Trash2, CheckCircle, Circle, Heart, Loader2 } from 'lucide-react' +import { ForumPost, ForumTopic } from '@/proxy/forum/forum' interface PostManagementProps { - posts: ForumPost[]; - topics: ForumTopic[]; - loading: boolean; - onCreatePost: (post: { - topicId: string; - content: string; - parentPostId?: string; - }) => Promise; - onUpdatePost: (id: string, post: Partial) => Promise; - onDeletePost: (id: string) => Promise; - onMarkPostAsAcceptedAnswer: (id: string) => Promise; - onUnmarkPostAsAcceptedAnswer: (id: string) => Promise; + posts: ForumPost[] + topics: ForumTopic[] + loading: boolean + onCreatePost: (post: { topicId: string; content: string; parentPostId?: string }) => Promise + onUpdatePost: (id: string, post: Partial) => Promise + onDeletePost: (id: string) => Promise + onMarkPostAsAcceptedAnswer: (id: string) => Promise + onUnmarkPostAsAcceptedAnswer: (id: string) => Promise } -export function PostManagement({ - posts, - topics, +export function PostManagement({ + posts, + topics, loading, - onCreatePost, - onUpdatePost, + onCreatePost, + onUpdatePost, onDeletePost, onMarkPostAsAcceptedAnswer, - onUnmarkPostAsAcceptedAnswer + onUnmarkPostAsAcceptedAnswer, }: PostManagementProps) { - const [showCreateForm, setShowCreateForm] = useState(false); - const [editingPost, setEditingPost] = useState(null); + const [showCreateForm, setShowCreateForm] = useState(false) + const [editingPost, setEditingPost] = useState(null) const [formData, setFormData] = useState({ topicId: '', content: '', isAcceptedAnswer: false, - }); - const [submitting, setSubmitting] = useState(false); + }) + const [submitting, setSubmitting] = useState(false) const resetForm = () => { setFormData({ topicId: '', content: '', isAcceptedAnswer: false, - }); - setShowCreateForm(false); - setEditingPost(null); - }; + }) + setShowCreateForm(false) + setEditingPost(null) + } const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (submitting) return; + e.preventDefault() + if (submitting) return try { - setSubmitting(true); + setSubmitting(true) if (editingPost) { - await onUpdatePost(editingPost.id, formData); + await onUpdatePost(editingPost.id, formData) } else { - await onCreatePost(formData); + await onCreatePost(formData) } - resetForm(); + resetForm() } catch (error) { - console.error('Error submitting form:', error); + console.error('Error submitting form:', error) } finally { - setSubmitting(false); + setSubmitting(false) } - }; + } const handleEdit = (post: ForumPost) => { - setEditingPost(post); + setEditingPost(post) setFormData({ topicId: post.topicId, content: post.content, isAcceptedAnswer: post.isAcceptedAnswer, - }); - setShowCreateForm(true); - }; + }) + setShowCreateForm(true) + } const handleToggleAcceptedAnswer = async (post: ForumPost) => { try { if (post.isAcceptedAnswer) { - await onUnmarkPostAsAcceptedAnswer(post.id); + await onUnmarkPostAsAcceptedAnswer(post.id) } else { - await onMarkPostAsAcceptedAnswer(post.id); + await onMarkPostAsAcceptedAnswer(post.id) } } catch (error) { - console.error('Error toggling accepted answer:', error); + console.error('Error toggling accepted answer:', error) } - }; + } const handleDelete = async (id: string) => { if (confirm('Are you sure you want to delete this post?')) { try { - await onDeletePost(id); + await onDeletePost(id) } catch (error) { - console.error('Error deleting post:', error); + console.error('Error deleting post:', error) } } - }; + } const getTopicTitle = (topicId: string) => { - const topic = topics.find(t => t.id === topicId); - return topic ? topic.title : 'Unknown Topic'; - }; + const topic = topics.find((t) => t.id === topicId) + return topic ? topic.title : 'Unknown Topic' + } + + const formatDate = (value: string | Date) => { + const date = value instanceof Date ? value : new Date(value) + if (isNaN(date.getTime())) return 'Invalid Date' - const formatDate = (date: Date) => { return new Intl.DateTimeFormat('en', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', - }).format(date); - }; + }).format(date) + } return (
@@ -142,14 +141,14 @@ export function PostManagement({ required > - {topics.map(topic => ( + {topics.map((topic) => ( ))}
- +