From bcd0e4514942fdfd900b5043b3d30f988d7e5aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Fri, 20 Jun 2025 14:11:42 +0300 Subject: [PATCH] =?UTF-8?q?Blog=20sistemindeki=20g=C3=BCncellemeler2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Blog/BlogPostDto.cs | 1 + .../Blog/IBlogAppService.cs | 21 +- .../Blog/BlogAppService.cs | 499 ++++-------------- .../Forum/ForumAppService.cs | 160 +++--- .../Seeds/PlatformDataSeeder.cs | 2 +- .../Seeds/SeederData.json | 459 ++++++++-------- .../Seeds/SeederDto.cs | 1 + .../Kurs.Platform.Domain/Blog/BlogComment.cs | 57 -- .../Blog/BlogCommentLike.cs | 31 -- api/src/Kurs.Platform.Domain/Blog/BlogPost.cs | 27 - .../Kurs.Platform.Domain/Blog/BlogPostLike.cs | 31 -- .../Kurs.Platform.Domain/Blog/BlogPostTag.cs | 31 -- .../EntityFrameworkCore/PlatformDbContext.cs | 64 --- ...20094517_AddBlogForumEntities.Designer.cs} | 223 +------- ...=> 20250620094517_AddBlogForumEntities.cs} | 149 +----- .../PlatformDbContextModelSnapshot.cs | 221 -------- company/src/locales/blogContent.ts | 203 ------- company/src/pages/Blog.tsx | 7 +- company/src/services/api/blog.service.ts | 51 +- company/src/store/authStore.ts | 10 +- ui/dev-dist/sw.js | 2 +- ui/src/constants/route.constant.ts | 4 +- ui/src/services/blog.service.ts | 4 + ui/src/views/blog/BlogManagement.tsx | 222 +++++--- ui/src/views/forum/ForumManagement.tsx | 40 +- 25 files changed, 593 insertions(+), 1927 deletions(-) delete mode 100644 api/src/Kurs.Platform.Domain/Blog/BlogComment.cs delete mode 100644 api/src/Kurs.Platform.Domain/Blog/BlogCommentLike.cs delete mode 100644 api/src/Kurs.Platform.Domain/Blog/BlogPostLike.cs delete mode 100644 api/src/Kurs.Platform.Domain/Blog/BlogPostTag.cs rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20250619205823_AddBlogForumEntities.Designer.cs => 20250620094517_AddBlogForumEntities.Designer.cs} (96%) rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20250619205823_AddBlogForumEntities.cs => 20250620094517_AddBlogForumEntities.cs} (72%) delete mode 100644 company/src/locales/blogContent.ts diff --git a/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs b/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs index daedbf77..c7033e64 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Blog/BlogPostDto.cs @@ -65,6 +65,7 @@ namespace Kurs.Platform.Blog public string Summary { get; set; } public string ReadTime { get; set; } public string CoverImage { get; set; } + public string Content { get; set; } public BlogCategoryDto Category { get; set; } public AuthorDto Author { get; set; } diff --git a/api/src/Kurs.Platform.Application.Contracts/Blog/IBlogAppService.cs b/api/src/Kurs.Platform.Application.Contracts/Blog/IBlogAppService.cs index cf83be36..d2c866f4 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Blog/IBlogAppService.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Blog/IBlogAppService.cs @@ -17,9 +17,6 @@ namespace Kurs.Platform.Blog Task DeletePostAsync(Guid id); Task PublishPostAsync(Guid id); Task UnpublishPostAsync(Guid id); - Task LikePostAsync(Guid id); - Task UnlikePostAsync(Guid id); - Task IncrementViewCountAsync(Guid id); // Blog Category methods Task> GetCategoriesAsync(); @@ -27,28 +24,12 @@ namespace Kurs.Platform.Blog Task CreateCategoryAsync(CreateUpdateBlogCategoryDto input); Task UpdateCategoryAsync(Guid id, CreateUpdateBlogCategoryDto input); Task DeleteCategoryAsync(Guid id); - - // Search and filters - Task> SearchPostsAsync(SearchBlogPostsInput input); - Task> GetPostsByCategoryAsync(Guid categoryId, PagedAndSortedResultRequestDto input); - Task> GetPostsByTagAsync(string tag, PagedAndSortedResultRequestDto input); - Task> GetPostsByAuthorAsync(Guid authorId, PagedAndSortedResultRequestDto input); - - // Tags - Task> GetPopularTagsAsync(int count = 20); - - // Stats - Task GetStatsAsync(); } public class GetBlogPostsInput : PagedAndSortedResultRequestDto { - public string Filter { get; set; } + public string Search { get; set; } public Guid? CategoryId { get; set; } - public string Tag { get; set; } - public Guid? AuthorId { get; set; } - public bool? IsPublished { get; set; } - public string SortBy { get; set; } = "latest"; // latest, popular, trending } public class SearchBlogPostsInput : PagedAndSortedResultRequestDto diff --git a/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs b/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs index e172dc8a..f6f937e6 100644 --- a/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs +++ b/api/src/Kurs.Platform.Application/Blog/BlogAppService.cs @@ -2,9 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Kurs.Platform.Localization; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Localization; using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories; using Volo.Abp.Users; @@ -12,139 +13,102 @@ using Volo.Abp.Users; namespace Kurs.Platform.Blog { [Authorize] - public class BlogAppService : ApplicationService, IBlogAppService + public class BlogAppService : PlatformAppService, IBlogAppService { private readonly IRepository _postRepository; private readonly IRepository _categoryRepository; - private readonly IRepository _tagRepository; - private readonly IRepository _postLikeRepository; private readonly ICurrentUser _currentUser; + private readonly IStringLocalizer _localizer; public BlogAppService( IRepository postRepository, IRepository categoryRepository, - IRepository tagRepository, - IRepository postLikeRepository, - ICurrentUser currentUser) + ICurrentUser currentUser, + IStringLocalizer localizer) { _postRepository = postRepository; _categoryRepository = categoryRepository; - _tagRepository = tagRepository; - _postLikeRepository = postLikeRepository; _currentUser = currentUser; + _localizer = localizer; } // Blog Post methods + [AllowAnonymous] public async Task> GetPostsAsync(GetBlogPostsInput input) { - var query = await _postRepository.GetQueryableAsync(); - - if (!string.IsNullOrWhiteSpace(input.Filter)) + var allPosts = await _postRepository.GetListAsync(); // Tüm kayıtlar memory'ye alınır + + var filtered = allPosts.Where(post => { - query = query.Where(x => x.Title.Contains(input.Filter) || x.Summary.Contains(input.Filter)); - } - - if (input.CategoryId.HasValue) - { - query = query.Where(x => x.CategoryId == input.CategoryId.Value); - } - - if (!string.IsNullOrWhiteSpace(input.Tag)) - { - var postIds = await _tagRepository - .GetListAsync(x => x.Tag == input.Tag) - .ContinueWith(t => t.Result.Select(x => x.PostId).ToList()); - - query = query.Where(x => postIds.Contains(x.Id)); - } - - if (input.AuthorId.HasValue) - { - query = query.Where(x => x.AuthorId == input.AuthorId.Value); - } - - if (input.IsPublished.HasValue) - { - query = query.Where(x => x.IsPublished == input.IsPublished.Value); - } - - // Sorting - if (input.SortBy == "popular") - { - query = query.OrderByDescending(x => x.LikeCount); - } - else if (input.SortBy == "trending") - { - query = query.OrderByDescending(x => x.ViewCount); - } - else // latest - { - query = query.OrderByDescending(x => x.CreationTime); - } - - var totalCount = await AsyncExecuter.CountAsync(query); - var posts = await AsyncExecuter.ToListAsync( - query.Skip(input.SkipCount).Take(input.MaxResultCount) - ); - - var postDtos = new List(); - foreach (var post in posts) + var localizedTitle = _localizer[post.Title].Value; + var localizedSummary = _localizer[post.Summary].Value; + + var searchMatch = string.IsNullOrWhiteSpace(input.Search) || + localizedTitle.Contains(input.Search, StringComparison.OrdinalIgnoreCase) || + localizedSummary.Contains(input.Search, StringComparison.OrdinalIgnoreCase); + + var categoryMatch = !input.CategoryId.HasValue || post.CategoryId == input.CategoryId.Value; + + return searchMatch && categoryMatch; + }).ToList(); + + var totalCount = filtered.Count; + + var pagedPosts = filtered + .OrderByDescending(x => x.CreationTime) + .Skip(input.SkipCount) + .Take(input.MaxResultCount) + .ToList(); + + var categoryIds = pagedPosts.Select(x => x.CategoryId).Distinct().ToList(); + var categories = await _categoryRepository.GetListAsync(x => categoryIds.Contains(x.Id)); + var categoryDict = categories.ToDictionary(x => x.Id, x => x); + + var postIds = pagedPosts.Select(x => x.Id).ToList(); + + var postDtos = pagedPosts.Select(post => { var dto = ObjectMapper.Map(post); - - // Get category - var category = await _categoryRepository.GetAsync(post.CategoryId); - dto.Category = ObjectMapper.Map(category); - - // Get tags - var tags = await _tagRepository.GetListAsync(x => x.PostId == post.Id); - dto.Tags = tags.Select(x => x.Tag).ToList(); - - // Get author info + + if (categoryDict.TryGetValue(post.CategoryId, out var category)) + { + dto.Category = ObjectMapper.Map(category); + } + dto.Author = new AuthorDto { Id = post.AuthorId, - Name = post.CreatorId.HasValue ? "User" : "Unknown" + Name = "User" }; - - postDtos.Add(dto); - } - + + return dto; + }).ToList(); + return new PagedResultDto(totalCount, postDtos); } + [AllowAnonymous] public async Task GetPostAsync(Guid id) { var post = await _postRepository.GetAsync(id); var dto = ObjectMapper.Map(post); - + // Get category dto.Category = ObjectMapper.Map( await _categoryRepository.GetAsync(post.CategoryId) ); - - // Get tags - var tags = await _tagRepository.GetListAsync(x => x.PostId == post.Id); - dto.Tags = tags.Select(x => x.Tag).ToList(); - + // Get author info dto.Author = new AuthorDto { Id = post.AuthorId, - Name = post.CreatorId.HasValue ? "User" : "Unknown" + Name = "User" }; - - // Check if current user liked this post - if (_currentUser.IsAuthenticated) - { - dto.IsLiked = await _postLikeRepository.AnyAsync( - x => x.PostId == id && x.UserId == _currentUser.Id.Value - ); - } - + return dto; } + [AllowAnonymous] public async Task GetPostBySlugAsync(string slug) { var post = await _postRepository.FirstOrDefaultAsync(x => x.Slug == slug); @@ -152,7 +116,7 @@ namespace Kurs.Platform.Blog { throw new EntityNotFoundException(typeof(BlogPost)); } - + return await GetPostAsync(post.Id); } @@ -170,187 +134,127 @@ namespace Kurs.Platform.Blog _currentUser.Id.Value, CurrentTenant.Id ); - + post.CoverImage = input.CoverImage; - + if (input.IsPublished) { post.Publish(); } - - await _postRepository.InsertAsync(post); - - // Add tags - foreach (var tag in input.Tags) - { - await _tagRepository.InsertAsync(new BlogPostTag( - GuidGenerator.Create(), - post.Id, - tag, - CurrentTenant.Id - )); - } - - // Update category post count - var category = await _categoryRepository.GetAsync(input.CategoryId); - category.IncrementPostCount(); - await _categoryRepository.UpdateAsync(category); - + + await _postRepository.InsertAsync(post, autoSave: true); + return await GetPostAsync(post.Id); } public async Task UpdatePostAsync(Guid id, CreateUpdateBlogPostDto input) { var post = await _postRepository.GetAsync(id); - - // Check if user is author or has permission + if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.Blog.Update")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + post.Title = input.Title; post.Slug = input.Slug; - post.Content = input.Content; post.Summary = input.Summary; post.CoverImage = input.CoverImage; - - // Update category if changed + post.Content = input.Content; + + if (input.IsPublished) post.Publish(); else post.Unpublish(); + if (post.CategoryId != input.CategoryId) { var oldCategory = await _categoryRepository.GetAsync(post.CategoryId); oldCategory.DecrementPostCount(); await _categoryRepository.UpdateAsync(oldCategory); - + var newCategory = await _categoryRepository.GetAsync(input.CategoryId); newCategory.IncrementPostCount(); await _categoryRepository.UpdateAsync(newCategory); - + post.CategoryId = input.CategoryId; } - + await _postRepository.UpdateAsync(post); - - // Update tags - await _tagRepository.DeleteAsync(x => x.PostId == id); - foreach (var tag in input.Tags) - { - await _tagRepository.InsertAsync(new BlogPostTag( - GuidGenerator.Create(), - post.Id, - tag, - CurrentTenant.Id - )); - } - - return await GetPostAsync(post.Id); + + return await GetPostAsync(post.Id); // ✅ DTO dönülüyor } public async Task DeletePostAsync(Guid id) { 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")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + // Update category post count var category = await _categoryRepository.GetAsync(post.CategoryId); category.DecrementPostCount(); await _categoryRepository.UpdateAsync(category); - + await _postRepository.DeleteAsync(id); } public async Task PublishPostAsync(Guid id) { 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")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + post.Publish(); await _postRepository.UpdateAsync(post); - + return await GetPostAsync(id); } public async Task UnpublishPostAsync(Guid id) { 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")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + post.Unpublish(); await _postRepository.UpdateAsync(post); - + return await GetPostAsync(id); } - public async Task LikePostAsync(Guid id) - { - var existingLike = await _postLikeRepository.FirstOrDefaultAsync( - x => x.PostId == id && x.UserId == _currentUser.Id.Value - ); - - if (existingLike == null) - { - await _postLikeRepository.InsertAsync(new BlogPostLike( - GuidGenerator.Create(), - id, - _currentUser.Id.Value, - CurrentTenant.Id - )); - - // Update like count - var post = await _postRepository.GetAsync(id); - var likeCount = await _postLikeRepository.CountAsync(x => x.PostId == id); - post.UpdateLikeCount((int)likeCount); - await _postRepository.UpdateAsync(post); - } - } - - public async Task UnlikePostAsync(Guid id) - { - var existingLike = await _postLikeRepository.FirstOrDefaultAsync( - x => x.PostId == id && x.UserId == _currentUser.Id.Value - ); - - if (existingLike != null) - { - await _postLikeRepository.DeleteAsync(existingLike); - - // Update like count - var post = await _postRepository.GetAsync(id); - var likeCount = await _postLikeRepository.CountAsync(x => x.PostId == id); - post.UpdateLikeCount((int)likeCount); - await _postRepository.UpdateAsync(post); - } - } - - [AllowAnonymous] - public async Task IncrementViewCountAsync(Guid id) - { - var post = await _postRepository.GetAsync(id); - post.IncrementViewCount(); - await _postRepository.UpdateAsync(post); - } - // Blog Category methods [AllowAnonymous] public async Task> GetCategoriesAsync() { - var categories = await _categoryRepository.GetListAsync(x => x.IsActive); - return ObjectMapper.Map, List>(categories); + var categories = await _categoryRepository.GetListAsync(); + + var postQuery = await _postRepository.GetQueryableAsync(); + + var groupedCounts = postQuery + .Where(p => p.IsPublished) // sadece yayınlanmış yazılar + .GroupBy(p => p.CategoryId) + .Select(g => new { CategoryId = g.Key, Count = g.Count() }) + .ToList(); + + var dtoList = ObjectMapper.Map, List>(categories); + + foreach (var dto in dtoList) + { + dto.PostCount = groupedCounts + .FirstOrDefault(x => x.CategoryId == dto.Id)?.Count ?? 0; + } + + return dtoList; } public async Task GetCategoryAsync(Guid id) @@ -369,13 +273,13 @@ namespace Kurs.Platform.Blog input.Description, CurrentTenant.Id ); - + category.Icon = input.Icon; category.DisplayOrder = input.DisplayOrder; category.IsActive = input.IsActive; - + await _categoryRepository.InsertAsync(category); - + return ObjectMapper.Map(category); } @@ -383,16 +287,16 @@ namespace Kurs.Platform.Blog public async Task UpdateCategoryAsync(Guid id, CreateUpdateBlogCategoryDto input) { var category = await _categoryRepository.GetAsync(id); - + category.Name = input.Name; category.Slug = input.Slug; category.Description = input.Description; category.Icon = input.Icon; category.DisplayOrder = input.DisplayOrder; category.IsActive = input.IsActive; - + await _categoryRepository.UpdateAsync(category); - + return ObjectMapper.Map(category); } @@ -405,198 +309,9 @@ namespace Kurs.Platform.Blog { throw new Volo.Abp.BusinessException("Cannot delete category with posts"); } - + await _categoryRepository.DeleteAsync(id); } - // Search and filters - public async Task> SearchPostsAsync(SearchBlogPostsInput input) - { - var query = await _postRepository.GetQueryableAsync(); - - if (!string.IsNullOrWhiteSpace(input.Query)) - { - query = query.Where(x => - x.Title.Contains(input.Query) || - x.Content.Contains(input.Query) || - x.Summary.Contains(input.Query) - ); - } - - if (input.CategoryId.HasValue) - { - query = query.Where(x => x.CategoryId == input.CategoryId.Value); - } - - if (input.AuthorId.HasValue) - { - query = query.Where(x => x.AuthorId == input.AuthorId.Value); - } - - if (input.IsPublished.HasValue) - { - query = query.Where(x => x.IsPublished == input.IsPublished.Value); - } - - // Search by tag - if (!string.IsNullOrWhiteSpace(input.Tag)) - { - var postIds = await _tagRepository - .GetListAsync(x => x.Tag == input.Tag) - .ContinueWith(t => t.Result.Select(x => x.PostId).ToList()); - - query = query.Where(x => postIds.Contains(x.Id)); - } - - var totalCount = await AsyncExecuter.CountAsync(query); - var posts = await AsyncExecuter.ToListAsync( - query.OrderByDescending(x => x.CreationTime) - .Skip(input.SkipCount) - .Take(input.MaxResultCount) - ); - - var postDtos = new List(); - foreach (var post in posts) - { - var dto = ObjectMapper.Map(post); - - // Get category - var category = await _categoryRepository.GetAsync(post.CategoryId); - dto.Category = ObjectMapper.Map(category); - - // Get tags - var tags = await _tagRepository.GetListAsync(x => x.PostId == post.Id); - dto.Tags = tags.Select(x => x.Tag).ToList(); - - // Get author info - dto.Author = new AuthorDto - { - Id = post.AuthorId, - Name = post.CreatorId.HasValue ? "User" : "Unknown" - }; - - postDtos.Add(dto); - } - - return new PagedResultDto(totalCount, postDtos); - } - - public async Task> GetPostsByCategoryAsync(Guid categoryId, PagedAndSortedResultRequestDto input) - { - var searchInput = new GetBlogPostsInput - { - CategoryId = categoryId, - MaxResultCount = input.MaxResultCount, - SkipCount = input.SkipCount, - Sorting = input.Sorting - }; - - return await GetPostsAsync(searchInput); - } - - public async Task> GetPostsByTagAsync(string tag, PagedAndSortedResultRequestDto input) - { - var searchInput = new GetBlogPostsInput - { - Tag = tag, - MaxResultCount = input.MaxResultCount, - SkipCount = input.SkipCount, - Sorting = input.Sorting - }; - - return await GetPostsAsync(searchInput); - } - - public async Task> GetPostsByAuthorAsync(Guid authorId, PagedAndSortedResultRequestDto input) - { - var searchInput = new GetBlogPostsInput - { - AuthorId = authorId, - MaxResultCount = input.MaxResultCount, - SkipCount = input.SkipCount, - Sorting = input.Sorting - }; - - return await GetPostsAsync(searchInput); - } - - // Tags - [AllowAnonymous] - public async Task> GetPopularTagsAsync(int count = 20) - { - var tags = await _tagRepository.GetListAsync(); - - return tags - .GroupBy(x => x.Tag) - .OrderByDescending(g => g.Count()) - .Take(count) - .Select(g => g.Key) - .ToList(); - } - - // Stats - [AllowAnonymous] - public async Task GetStatsAsync() - { - var stats = new BlogStatsDto - { - TotalPosts = (int)await _postRepository.CountAsync(), - PublishedPosts = (int)await _postRepository.CountAsync(x => x.IsPublished), - DraftPosts = (int)await _postRepository.CountAsync(x => !x.IsPublished), - TotalCategories = (int)await _categoryRepository.CountAsync(x => x.IsActive), - TotalViews = (await _postRepository.GetListAsync()).Sum(x => x.ViewCount), - TotalLikes = (await _postRepository.GetListAsync()).Sum(x => x.LikeCount), - TotalComments = 0, // You should implement comment count - PopularTags = await GetPopularTagsAsync(10) - }; - - // Get latest post - var latestPost = await _postRepository - .GetQueryableAsync() - .ContinueWith(async t => - { - var query = await t; - return await AsyncExecuter.FirstOrDefaultAsync( - query.Where(x => x.IsPublished).OrderByDescending(x => x.CreationTime) - ); - }) - .Unwrap(); - - if (latestPost != null) - { - var dto = ObjectMapper.Map(latestPost); - - // Get category - var category = await _categoryRepository.GetAsync(latestPost.CategoryId); - dto.Category = ObjectMapper.Map(category); - - stats.LatestPost = dto; - } - - // Get most viewed post - var mostViewedPost = await _postRepository - .GetQueryableAsync() - .ContinueWith(async t => - { - var query = await t; - return await AsyncExecuter.FirstOrDefaultAsync( - query.Where(x => x.IsPublished).OrderByDescending(x => x.ViewCount) - ); - }) - .Unwrap(); - - if (mostViewedPost != null) - { - var dto = ObjectMapper.Map(mostViewedPost); - - // Get category - var category = await _categoryRepository.GetAsync(mostViewedPost.CategoryId); - dto.Category = ObjectMapper.Map(category); - - stats.MostViewedPost = dto; - } - - return stats; - } } } diff --git a/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs b/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs index 96c3df82..0037c193 100644 --- a/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs +++ b/api/src/Kurs.Platform.Application/Forum/ForumAppService.cs @@ -40,7 +40,7 @@ namespace Kurs.Platform.Forum public async Task> GetCategoriesAsync() { var categories = await _categoryRepository.GetListAsync(x => x.IsActive); - + return ObjectMapper.Map, List>(categories); } @@ -83,7 +83,7 @@ namespace Kurs.Platform.Forum post.Author = new AuthorDto { Id = topic.AuthorId, - Name = topic.CreatorId.HasValue ? "User" : "Unknown" + Name = "User" }; // Get tags @@ -126,19 +126,19 @@ namespace Kurs.Platform.Forum input.DisplayOrder, CurrentTenant.Id ); - + category.IsActive = input.IsActive; category.IsLocked = input.IsLocked; await _categoryRepository.InsertAsync(category); - + return ObjectMapper.Map(category); } public async Task UpdateCategoryAsync(Guid id, CreateUpdateForumCategoryDto input) { var category = await _categoryRepository.GetAsync(id); - + category.Name = input.Name; category.Slug = input.Slug; category.Description = input.Description; @@ -146,9 +146,9 @@ namespace Kurs.Platform.Forum category.DisplayOrder = input.DisplayOrder; category.IsActive = input.IsActive; category.IsLocked = input.IsLocked; - + await _categoryRepository.UpdateAsync(category); - + return ObjectMapper.Map(category); } @@ -161,32 +161,32 @@ namespace Kurs.Platform.Forum public async Task> GetTopicsAsync(GetForumTopicsInput input) { var query = await _topicRepository.GetQueryableAsync(); - + if (input.CategoryId.HasValue) { query = query.Where(x => x.CategoryId == input.CategoryId.Value); } - + if (!string.IsNullOrWhiteSpace(input.Filter)) { query = query.Where(x => x.Title.Contains(input.Filter)); } - + if (input.IsPinned.HasValue) { query = query.Where(x => x.IsPinned == input.IsPinned.Value); } - + if (input.IsLocked.HasValue) { query = query.Where(x => x.IsLocked == input.IsLocked.Value); } - + if (input.IsSolved.HasValue) { query = query.Where(x => x.IsSolved == input.IsSolved.Value); } - + // Sorting if (input.SortBy == "popular") { @@ -200,35 +200,35 @@ namespace Kurs.Platform.Forum { query = query.OrderByDescending(x => x.CreationTime); } - + var totalCount = await AsyncExecuter.CountAsync(query); var topics = await AsyncExecuter.ToListAsync( query.Skip(input.SkipCount).Take(input.MaxResultCount) ); - + var topicDtos = new List(); foreach (var topic in topics) { var dto = ObjectMapper.Map(topic); - + // Get category name var category = await _categoryRepository.GetAsync(topic.CategoryId); dto.CategoryName = category.Name; - + // Get author info dto.Author = new AuthorDto { Id = topic.AuthorId, - Name = topic.CreatorId.HasValue ? "User" : "Unknown" // You should get actual user name + Name = "User" }; - + // Get tags var tags = await _tagRepository.GetListAsync(x => x.TopicId == topic.Id); dto.Tags = tags.Select(x => x.Tag).ToList(); - + topicDtos.Add(dto); } - + return new PagedResultDto(totalCount, topicDtos); } @@ -236,23 +236,23 @@ namespace Kurs.Platform.Forum { var topic = await _topicRepository.GetAsync(id); var dto = ObjectMapper.Map(topic); - + // Get category dto.Category = ObjectMapper.Map( await _categoryRepository.GetAsync(topic.CategoryId) ); - + // Get author info dto.Author = new AuthorDto { Id = topic.AuthorId, - Name = topic.CreatorId.HasValue ? "User" : "Unknown" // You should get actual user name + Name = "User" }; - + // Get tags var tags = await _tagRepository.GetListAsync(x => x.TopicId == topic.Id); dto.Tags = tags.Select(x => x.Tag).ToList(); - + // Check if current user liked this topic if (_currentUser.IsAuthenticated) { @@ -260,7 +260,7 @@ namespace Kurs.Platform.Forum x => x.TopicId == id && x.UserId == _currentUser.Id.Value ); } - + return dto; } @@ -274,9 +274,9 @@ namespace Kurs.Platform.Forum _currentUser.Id.Value, CurrentTenant.Id ); - + await _topicRepository.InsertAsync(topic); - + // Add tags foreach (var tag in input.Tags) { @@ -287,30 +287,30 @@ namespace Kurs.Platform.Forum CurrentTenant.Id )); } - + // Update category counts var category = await _categoryRepository.GetAsync(input.CategoryId); category.IncrementTopicCount(); await _categoryRepository.UpdateAsync(category); - + return await GetTopicAsync(topic.Id); } public async Task UpdateTopicAsync(Guid id, UpdateForumTopicDto input) { var topic = await _topicRepository.GetAsync(id); - + // Check if user is author or has permission if (topic.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("Forum.Topics.Update")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + topic.Title = input.Title; topic.Content = input.Content; - + await _topicRepository.UpdateAsync(topic); - + // Update tags await _tagRepository.DeleteAsync(x => x.TopicId == id); foreach (var tag in input.Tags) @@ -322,25 +322,25 @@ namespace Kurs.Platform.Forum CurrentTenant.Id )); } - + return await GetTopicAsync(topic.Id); } public async Task DeleteTopicAsync(Guid id) { var topic = await _topicRepository.GetAsync(id); - + // Check if user is author or has permission if (topic.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("Forum.Topics.Delete")) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + // Update category counts var category = await _categoryRepository.GetAsync(topic.CategoryId); category.DecrementTopicCount(); await _categoryRepository.UpdateAsync(category); - + await _topicRepository.DeleteAsync(id); } @@ -380,13 +380,13 @@ namespace Kurs.Platform.Forum public async Task MarkAsSolvedAsync(Guid id) { var topic = await _topicRepository.GetAsync(id); - + // Only author can mark as solved if (topic.AuthorId != _currentUser.Id) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + topic.MarkAsSolved(); await _topicRepository.UpdateAsync(topic); return await GetTopicAsync(id); @@ -395,13 +395,13 @@ namespace Kurs.Platform.Forum public async Task MarkAsUnsolvedAsync(Guid id) { var topic = await _topicRepository.GetAsync(id); - + // Only author can mark as unsolved if (topic.AuthorId != _currentUser.Id) { throw new Volo.Abp.Authorization.AbpAuthorizationException(); } - + topic.MarkAsUnsolved(); await _topicRepository.UpdateAsync(topic); return await GetTopicAsync(id); @@ -412,7 +412,7 @@ namespace Kurs.Platform.Forum var existingLike = await _topicLikeRepository.FirstOrDefaultAsync( x => x.TopicId == id && x.UserId == _currentUser.Id.Value ); - + if (existingLike == null) { await _topicLikeRepository.InsertAsync(new ForumTopicLike( @@ -421,7 +421,7 @@ namespace Kurs.Platform.Forum _currentUser.Id.Value, CurrentTenant.Id )); - + // Update like count var topic = await _topicRepository.GetAsync(id); var likeCount = await _topicLikeRepository.CountAsync(x => x.TopicId == id); @@ -435,11 +435,11 @@ namespace Kurs.Platform.Forum var existingLike = await _topicLikeRepository.FirstOrDefaultAsync( x => x.TopicId == id && x.UserId == _currentUser.Id.Value ); - + if (existingLike != null) { await _topicLikeRepository.DeleteAsync(existingLike); - + // Update like count var topic = await _topicRepository.GetAsync(id); var likeCount = await _topicLikeRepository.CountAsync(x => x.TopicId == id); @@ -460,70 +460,70 @@ namespace Kurs.Platform.Forum public async Task> SearchTopicsAsync(SearchForumTopicsInput input) { var query = await _topicRepository.GetQueryableAsync(); - + if (!string.IsNullOrWhiteSpace(input.Query)) { - query = query.Where(x => - x.Title.Contains(input.Query) || + query = query.Where(x => + x.Title.Contains(input.Query) || x.Content.Contains(input.Query) ); } - + if (input.CategoryId.HasValue) { query = query.Where(x => x.CategoryId == input.CategoryId.Value); } - + if (input.AuthorId.HasValue) { query = query.Where(x => x.AuthorId == input.AuthorId.Value); } - + if (input.IsSolved.HasValue) { query = query.Where(x => x.IsSolved == input.IsSolved.Value); } - + // Search by tag if (!string.IsNullOrWhiteSpace(input.Tag)) { var topicIds = await _tagRepository .GetListAsync(x => x.Tag == input.Tag) .ContinueWith(t => t.Result.Select(x => x.TopicId).ToList()); - + query = query.Where(x => topicIds.Contains(x.Id)); } - + var totalCount = await AsyncExecuter.CountAsync(query); var topics = await AsyncExecuter.ToListAsync( query.OrderByDescending(x => x.CreationTime) .Skip(input.SkipCount) .Take(input.MaxResultCount) ); - + var topicDtos = new List(); foreach (var topic in topics) { var dto = ObjectMapper.Map(topic); - + // Get category name var category = await _categoryRepository.GetAsync(topic.CategoryId); dto.CategoryName = category.Name; - + // Get author info dto.Author = new AuthorDto { Id = topic.AuthorId, - Name = topic.CreatorId.HasValue ? "User" : "Unknown" + Name = "User" }; - + // Get tags var tags = await _tagRepository.GetListAsync(x => x.TopicId == topic.Id); dto.Tags = tags.Select(x => x.Tag).ToList(); - + topicDtos.Add(dto); } - + return new PagedResultDto(totalCount, topicDtos); } @@ -535,40 +535,40 @@ namespace Kurs.Platform.Forum SkipCount = input.SkipCount, Sorting = input.Sorting }; - + var query = await _topicRepository.GetQueryableAsync(); query = query.Where(x => x.AuthorId == _currentUser.Id.Value); - + var totalCount = await AsyncExecuter.CountAsync(query); var topics = await AsyncExecuter.ToListAsync( query.OrderByDescending(x => x.CreationTime) .Skip(input.SkipCount) .Take(input.MaxResultCount) ); - + var topicDtos = new List(); foreach (var topic in topics) { var dto = ObjectMapper.Map(topic); - + // Get category name var category = await _categoryRepository.GetAsync(topic.CategoryId); dto.CategoryName = category.Name; - + // Get author info dto.Author = new AuthorDto { Id = topic.AuthorId, Name = _currentUser.Name ?? _currentUser.UserName }; - + // Get tags var tags = await _tagRepository.GetListAsync(x => x.TopicId == topic.Id); dto.Tags = tags.Select(x => x.Tag).ToList(); - + topicDtos.Add(dto); } - + return new PagedResultDto(totalCount, topicDtos); } @@ -581,7 +581,7 @@ namespace Kurs.Platform.Forum SkipCount = input.SkipCount, Sorting = input.Sorting }; - + return await SearchTopicsAsync(searchInput); } @@ -598,11 +598,11 @@ namespace Kurs.Platform.Forum OnlineUsers = 10, // You should implement online user tracking PopularTags = await GetPopularTagsAsync(10) }; - + // Get latest topic var latestTopic = await _topicRepository .GetQueryableAsync() - .ContinueWith(async t => + .ContinueWith(async t => { var query = await t; return await AsyncExecuter.FirstOrDefaultAsync( @@ -610,25 +610,25 @@ namespace Kurs.Platform.Forum ); }) .Unwrap(); - + if (latestTopic != null) { var dto = ObjectMapper.Map(latestTopic); - + // Get category name var category = await _categoryRepository.GetAsync(latestTopic.CategoryId); dto.CategoryName = category.Name; - + // Get author info dto.Author = new AuthorDto { Id = latestTopic.AuthorId, Name = "User" }; - + stats.LatestTopic = dto; } - + return stats; } @@ -636,7 +636,7 @@ namespace Kurs.Platform.Forum public async Task> GetPopularTagsAsync(int count = 20) { var tags = await _tagRepository.GetListAsync(); - + return tags .GroupBy(x => x.Tag) .OrderByDescending(g => g.Count()) diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs index 0c251843..64b45aa4 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs @@ -565,7 +565,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency ) { DisplayOrder = item.DisplayOrder, - PostCount = 1 + PostCount = item.PostCount }; await _blogCategoryRepository.InsertAsync(newCategory); diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json index 21e5b26b..7a177960 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json @@ -4631,6 +4631,150 @@ "key": "AI.AnalizAnswer", "en": "Analysis and Evaluation", "tr": "Analiz & Değerlendirme" + }, + { + "resourceName": "Platform", + "key": "blog.posts.ai.title", + "tr": "Yapay zekanın iş süreçlerine etkileri ve geleceği...", + "en": "Artificial Intelligence and Business" + }, + { + "resourceName": "Platform", + "key": "blog.posts.ai.excerpt", + "tr": "Yapay zekanın iş süreçlerine etkileri ve geleceği...", + "en": "The impacts and future of AI in business processes..." + }, + { + "resourceName": "Platform", + "key": "blog.posts.ai.date", + "tr": "10 Mayıs 2024", + "en": "May 10, 2024" + }, + { + "resourceName": "Platform", + "key": "blog.categories.technology", + "tr": "Teknoloji", + "en": "Technology" + }, + { + "resourceName": "Platform", + "key": "blog.posts.web.title", + "tr": "Web Geliştirmede Son Trendler", + "en": "Latest Trends in Web Development" + }, + { + "resourceName": "Platform", + "key": "blog.posts.web.excerpt", + "tr": "Modern web geliştirme teknikleri ve araçları...", + "en": "Modern web development techniques and tools..." + }, + { + "resourceName": "Platform", + "key": "blog.posts.web.date", + "tr": "5 Mayıs 2024", + "en": "May 5, 2024" + }, + { + "resourceName": "Platform", + "key": "blog.categories.webdev", + "tr": "Web Geliştirme", + "en": "Web Development" + }, + { + "resourceName": "Platform", + "key": "blog.posts.security.title", + "tr": "Siber Güvenlik İpuçları", + "en": "Cybersecurity Tips" + }, + { + "resourceName": "Platform", + "key": "blog.posts.security.excerpt", + "tr": "İşletmenizi siber tehditlere karşı koruyun...", + "en": "Protect your business against cyber threats..." + }, + { + "resourceName": "Platform", + "key": "blog.posts.security.date", + "tr": "1 Mayıs 2024", + "en": "May 1, 2024" + }, + { + "resourceName": "Platform", + "key": "blog.categories.security", + "tr": "Siber Güvenlik", + "en": "Cybersecurity" + }, + { + "resourceName": "Platform", + "key": "blog.posts.mobile.title", + "tr": "Mobil Uygulama Geliştirme Rehberi", + "en": "Mobile App Development Guide" + }, + { + "resourceName": "Platform", + "key": "blog.posts.mobile.excerpt", + "tr": "Başarılı bir mobil uygulama geliştirmek için ipuçları...", + "en": "Tips for building a successful mobile app..." + }, + { + "resourceName": "Platform", + "key": "blog.posts.mobile.date", + "tr": "25 Nisan 2024", + "en": "April 25, 2024" + }, + { + "resourceName": "Platform", + "key": "blog.categories.mobile", + "tr": "Mobil", + "en": "Mobile" + }, + { + "resourceName": "Platform", + "key": "blog.posts.database.title", + "tr": "Veritabanı Yönetimi Temelleri", + "en": "Fundamentals of Database Management" + }, + { + "resourceName": "Platform", + "key": "blog.posts.database.excerpt", + "tr": "Veritabanı tasarımı ve optimizasyonu...", + "en": "Database design and optimization..." + }, + { + "resourceName": "Platform", + "key": "blog.posts.database.date", + "tr": "20 Nisan 2024", + "en": "April 20, 2024" + }, + { + "resourceName": "Platform", + "key": "blog.categories.database", + "tr": "Veritabanı", + "en": "Database" + }, + { + "resourceName": "Platform", + "key": "blog.posts.digital.title", + "tr": "Dijital Pazarlama Stratejileri", + "en": "Digital Marketing Strategies" + }, + { + "resourceName": "Platform", + "key": "blog.posts.digital.excerpt", + "tr": "İşletmenizi dijital dünyada büyütün...", + "en": "Grow your business in the digital world..." + }, + { + "resourceName": "Platform", + "key": "blog.posts.digital.date", + "tr": "blog.posts.digital.date", + "en": "April 15, 2024" + }, + { + "resourceName": "Platform", + "key": "blog.categories.digital", + "tr": "Dijital Pazarlama", + "en": "Digital Marketing" } ], "Settings": [ @@ -4640,10 +4784,7 @@ "descriptionKey": "Abp.Localization.DefaultLanguage.Description", "defaultValue": "en", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -4677,10 +4818,7 @@ "descriptionKey": "Abp.Localization.Timezone.Description", "defaultValue": "UTC", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -4836,11 +4974,7 @@ "descriptionKey": "App.SiteManagement.Theme.Style.Description", "defaultValue": "dx.light.compact", "isVisibleToClients": true, - "providers": [ - "U", - "G", - "D" - ], + "providers": ["U", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -4888,10 +5022,7 @@ "descriptionKey": "App.SiteManagement.General.NewMemberNotificationEmails.Description", "defaultValue": "system@sozsoft.com", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -4907,10 +5038,7 @@ "descriptionKey": "App.SiteManagement.General.TimedLoginEmails.Description", "defaultValue": "system@sozsoft.com", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -4926,11 +5054,7 @@ "descriptionKey": "App.Sender.Sms.PostaGuvercini.Url.Description", "defaultValue": "https://www.postaguvercini.com/api_http", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -4946,11 +5070,7 @@ "descriptionKey": "App.Sender.Sms.PostaGuvercini.Username.Description", "defaultValue": "2AIlj4QlCrvlbDDBS/712A==", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": true, "mainGroupKey": "App.Sender", @@ -4966,11 +5086,7 @@ "descriptionKey": "App.Sender.Sms.PostaGuvercini.Password.Description", "defaultValue": "oTuwyZM9sxfJI+jDH5wJAw==", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": true, "mainGroupKey": "App.Sender", @@ -4986,11 +5102,7 @@ "descriptionKey": "App.Sender.WhatsApp.Url.Description", "defaultValue": "https://graph.facebook.com/v21.0", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5006,11 +5118,7 @@ "descriptionKey": "App.Sender.WhatsApp.PhoneNumberId.Description", "defaultValue": "442035112335974", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5026,11 +5134,7 @@ "descriptionKey": "App.Sender.WhatsApp.Token.Description", "defaultValue": "EAANoftqZAJ64BO5oPwXPqniUtNGF70u8TKvQVzGZBaYQh5UY8fYrgQkcXP9UbQUqT9PWRah1L7TzcBIiWQMacT8AkmZB33AP1begLoywIZCsQSdBSUz21GQaCowfVosYgBoXSyqH8irSBPQDLIjxxVxrC2n76SD9X6zPXeHgOqIPY92DqJXplstWrlhtZCAZDZD", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5046,11 +5150,7 @@ "descriptionKey": "App.Sender.WhatsApp.TemplateName.Description", "defaultValue": "kurs_platform_notification", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5066,10 +5166,7 @@ "descriptionKey": "App.Sender.Rocket.Url.Description", "defaultValue": "https://chat.sozsoft.com/api/v1", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5085,10 +5182,7 @@ "descriptionKey": "App.Sender.Rocket.UserId.Description", "defaultValue": "LfpzPjzag4QJXm84N", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5104,10 +5198,7 @@ "descriptionKey": "App.Sender.Rocket.Token.Description", "defaultValue": "jvqALawvXn0Q7c6FfHJV3h58DCHDfQLgFF5y7oIc7oc", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.Sender", @@ -5123,11 +5214,7 @@ "descriptionKey": "Abp.Mailing.DefaultFromDisplayName.Description", "defaultValue": "Kurs", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5143,11 +5230,7 @@ "descriptionKey": "Abp.Mailing.DefaultFromAddress.Description", "defaultValue": "system@sozsoft.com", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5163,11 +5246,7 @@ "descriptionKey": "Abp.Mailing.Smtp.UserName.Description", "defaultValue": "system@sozsoft.com", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5183,11 +5262,7 @@ "descriptionKey": "Abp.Mailing.Smtp.Password.Description", "defaultValue": "QT9L7BCl1CT/1Hq19HoSlQ==", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": true, "mainGroupKey": "Abp.Mailing", @@ -5203,11 +5278,7 @@ "descriptionKey": "Abp.Mailing.Smtp.Host.Description", "defaultValue": "127.0.0.1", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5223,11 +5294,7 @@ "descriptionKey": "Abp.Mailing.Smtp.Port.Description", "defaultValue": "25", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5243,11 +5310,7 @@ "descriptionKey": "Abp.Mailing.Smtp.Domain.Description", "defaultValue": "sozsoft.com", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5263,11 +5326,7 @@ "descriptionKey": "Abp.Mailing.Smtp.EnableSsl.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5283,11 +5342,7 @@ "descriptionKey": "Abp.Mailing.AWS.Profile.Description", "defaultValue": "mail-sdk-user", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5303,11 +5358,7 @@ "descriptionKey": "Abp.Mailing.AWS.Region.Description", "defaultValue": "eu-central-1", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5323,11 +5374,7 @@ "descriptionKey": "Abp.Mailing.AWS.AccessKey.Description", "defaultValue": "aXW8L21rP6dPO6Txj76Be2FCpWRBa25EMrSAVL76", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5343,11 +5390,7 @@ "descriptionKey": "Abp.Mailing.AWS.AccessKeyId.Description", "defaultValue": "AKIATULUYBLX4IY3S2P1", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Mailing", @@ -5363,10 +5406,7 @@ "descriptionKey": "Abp.Account.IsSelfRegistrationEnabled.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5382,10 +5422,7 @@ "descriptionKey": "Abp.Account.EnableLocalLogin.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5401,11 +5438,7 @@ "descriptionKey": "Abp.Account.TwoFactor.Enabled.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5421,10 +5454,7 @@ "descriptionKey": "Abp.Account.Captcha.MaxFailedAccessAttempts.Description", "defaultValue": "3", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5440,10 +5470,7 @@ "descriptionKey": "Abp.Account.Captcha.EndPoint.Description", "defaultValue": "https://challenges.cloudflare.com/turnstile/v0/siteverify", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5459,10 +5486,7 @@ "descriptionKey": "Abp.Account.Captcha.SiteKey.Description", "defaultValue": "0x4AAAAAAAGadwQME-GSYuJU", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5478,10 +5502,7 @@ "descriptionKey": "Abp.Account.Captcha.SecretKey.Description", "defaultValue": "0x4AAAAAAAGad_f_WP47IcNBs9FTu5DhNX8", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Account", @@ -5497,11 +5518,7 @@ "descriptionKey": "Abp.Identity.Profile.General.RequireVerifiedAccount.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5517,11 +5534,7 @@ "descriptionKey": "Abp.Identity.Profile.General.BlacklistedEmailProviders.Description", "defaultValue": "gmail.com\r\nyahoo.com\r\nhotmail.com", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5537,11 +5550,7 @@ "descriptionKey": "Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5557,11 +5566,7 @@ "descriptionKey": "Abp.Identity.Password.PasswordChangePeriodDays.Description", "defaultValue": "0", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5577,11 +5582,7 @@ "descriptionKey": "Abp.Identity.Password.RequiredLength.Description", "defaultValue": "6", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5597,11 +5598,7 @@ "descriptionKey": "Abp.Identity.Password.RequiredUniqueChars.Description", "defaultValue": "1", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5617,11 +5614,7 @@ "descriptionKey": "Abp.Identity.Password.RequireNonAlphanumeric.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5637,11 +5630,7 @@ "descriptionKey": "Abp.Identity.Password.RequireLowercase.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5657,11 +5646,7 @@ "descriptionKey": "Abp.Identity.Password.RequireUppercase.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5677,11 +5662,7 @@ "descriptionKey": "Abp.Identity.Password.RequireDigit.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5697,11 +5678,7 @@ "descriptionKey": "Abp.Identity.Lockout.AllowedForNewUsers.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5717,11 +5694,7 @@ "descriptionKey": "Abp.Identity.Lockout.LockoutDuration.Description", "defaultValue": "300", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5737,11 +5710,7 @@ "descriptionKey": "Abp.Identity.Lockout.MaxFailedAccessAttempts.Description", "defaultValue": "5", "isVisibleToClients": false, - "providers": [ - "T", - "G", - "D" - ], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5757,10 +5726,7 @@ "descriptionKey": "Abp.Identity.SignIn.RequireConfirmedEmail.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5776,10 +5742,7 @@ "descriptionKey": "Abp.Identity.SignIn.RequireConfirmedPhoneNumber.Description", "defaultValue": "False", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5795,10 +5758,7 @@ "descriptionKey": "Abp.Identity.User.IsUserNameUpdateEnabled.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -5814,10 +5774,7 @@ "descriptionKey": "Abp.Identity.User.IsEmailUpdateEnabled.Description", "defaultValue": "True", "isVisibleToClients": false, - "providers": [ - "G", - "D" - ], + "providers": ["G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "Abp.Identity", @@ -6182,7 +6139,7 @@ "Code": "App.Blog", "DisplayName": "App.Blog", "Order": 10, - "Url": "/admin/blog/management", + "Url": "/admin/blog", "Icon": "FcTemplate", "RequiredPermissionName": "App.Blog", "IsDisabled": false @@ -6192,7 +6149,7 @@ "Code": "App.Forum", "DisplayName": "App.Forum", "Order": 11, - "Url": "/admin/forum/management", + "Url": "/admin/forum", "Icon": "FcReading", "RequiredPermissionName": "App.Forum", "IsDisabled": false @@ -7601,7 +7558,7 @@ "GroupName": "App.Blog", "Name": "App.Blog.Publish", "ParentName": "App.Blog", - "DisplayName": "Export", + "DisplayName": "Publish", "IsEnabled": true, "MultiTenancySide": 2 }, @@ -20083,42 +20040,48 @@ "Name": "blog.categories.technology", "Slug": "ai-ve-gelecegi", "Description": "blog.posts.ai.excerpt", - "DisplayOrder": 1 + "DisplayOrder": 1, + "PostCount": 1 }, { "Id": "6d0ae65d-8b91-5bbf-879d-87ee25410458", "Name": "blog.categories.webdev", "Slug": "web-gelistirmede-son-trendler", "Description": "blog.posts.web.excerpt", - "DisplayOrder": 2 + "DisplayOrder": 2, + "PostCount": 1 }, { "Id": "e938e6e6-f355-5807-a7f7-f0d4fe368fc5", "Name": "blog.categories.security", "Slug": "siber-guvenlik-tehditleri-ve-korunma-yollari", "Description": "blog.posts.security.excerpt", - "DisplayOrder": 3 + "DisplayOrder": 3, + "PostCount": 1 }, { "Id": "ebd1b9aa-14ce-5c0b-9514-a4cbd5a7cf94", "Name": "blog.categories.mobile", "Slug": "mobil-uygulama-gelistirmede-cross-platform-cozumler", "Description": "blog.posts.mobile.excerpt", - "DisplayOrder": 4 + "DisplayOrder": 4, + "PostCount": 1 }, { "Id": "741ef542-0591-5472-9bf2-593047eb4122", "Name": "blog.categories.database", "Slug": "veritabani-yonetim-sistemleri-karsilastirmasi", "Description": "blog.posts.database.excerpt", - "DisplayOrder": 5 + "DisplayOrder": 5, + "PostCount": 1 }, { "Id": "dbc8578c-1a99-594a-8997-bddd0eac8571", "Name": "blog.categories.digital", "Slug": "dijital-pazarlamada-veri-analizi", "Description": "blog.posts.digital.excerpt", - "DisplayOrder": 6 + "DisplayOrder": 6, + "PostCount": 1 } ], "BlogPosts": [ @@ -20194,4 +20157,4 @@ "AuthorId": "727ec3f0-75dd-54e2-8ae6-13d49727ff58" } ] -} \ No newline at end of file +} diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs index b73b75d9..0238269d 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs @@ -207,6 +207,7 @@ public class BlogCategorySeedDto public string Slug { get; set; } public string Description { get; set; } public int DisplayOrder { get; set; } + public int PostCount { get; set; } } public class BlogPostSeedDto diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogComment.cs b/api/src/Kurs.Platform.Domain/Blog/BlogComment.cs deleted file mode 100644 index 64fcf858..00000000 --- a/api/src/Kurs.Platform.Domain/Blog/BlogComment.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Kurs.Platform.Blog -{ - public class BlogComment : FullAuditedEntity, IMultiTenant - { - public Guid? TenantId { get; set; } - - public Guid PostId { get; set; } - public virtual BlogPost Post { get; set; } - - public string Content { get; set; } - - public Guid AuthorId { get; set; } - - public Guid? ParentId { get; set; } - public virtual BlogComment Parent { get; set; } - - public virtual ICollection Replies { get; set; } - public virtual ICollection Likes { get; set; } - - public int LikeCount { get; set; } - - protected BlogComment() - { - Replies = new HashSet(); - Likes = new HashSet(); - } - - public BlogComment( - Guid id, - Guid postId, - string content, - Guid authorId, - Guid? parentId = null, - Guid? tenantId = null) : base(id) - { - PostId = postId; - Content = content; - AuthorId = authorId; - ParentId = parentId; - TenantId = tenantId; - LikeCount = 0; - - Replies = new HashSet(); - Likes = new HashSet(); - } - - public void UpdateLikeCount(int count) - { - LikeCount = count; - } - } -} diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogCommentLike.cs b/api/src/Kurs.Platform.Domain/Blog/BlogCommentLike.cs deleted file mode 100644 index 19fa09f5..00000000 --- a/api/src/Kurs.Platform.Domain/Blog/BlogCommentLike.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Kurs.Platform.Blog -{ - public class BlogCommentLike : CreationAuditedEntity, IMultiTenant - { - public Guid? TenantId { get; set; } - - public Guid CommentId { get; set; } - public virtual BlogComment Comment { get; set; } - - public Guid UserId { get; set; } - - protected BlogCommentLike() - { - } - - public BlogCommentLike( - Guid id, - Guid commentId, - Guid userId, - Guid? tenantId = null) : base(id) - { - CommentId = commentId; - UserId = userId; - TenantId = tenantId; - } - } -} diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs b/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs index 8e6c746f..453d9c61 100644 --- a/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs +++ b/api/src/Kurs.Platform.Domain/Blog/BlogPost.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; @@ -28,15 +27,8 @@ namespace Kurs.Platform.Blog public bool IsPublished { get; set; } public DateTime? PublishedAt { get; set; } - public virtual ICollection Tags { get; set; } - public virtual ICollection Comments { get; set; } - public virtual ICollection Likes { get; set; } - protected BlogPost() { - Tags = new HashSet(); - Comments = new HashSet(); - Likes = new HashSet(); } public BlogPost( @@ -65,10 +57,6 @@ namespace Kurs.Platform.Blog LikeCount = 0; CommentCount = 0; IsPublished = false; - - Tags = new HashSet(); - Comments = new HashSet(); - Likes = new HashSet(); } public void Publish() @@ -82,20 +70,5 @@ namespace Kurs.Platform.Blog IsPublished = false; PublishedAt = null; } - - public void IncrementViewCount() - { - ViewCount++; - } - - public void UpdateLikeCount(int count) - { - LikeCount = count; - } - - public void UpdateCommentCount(int count) - { - CommentCount = count; - } } } diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogPostLike.cs b/api/src/Kurs.Platform.Domain/Blog/BlogPostLike.cs deleted file mode 100644 index c4e2c1e9..00000000 --- a/api/src/Kurs.Platform.Domain/Blog/BlogPostLike.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Kurs.Platform.Blog -{ - public class BlogPostLike : CreationAuditedEntity, IMultiTenant - { - public Guid? TenantId { get; set; } - - public Guid PostId { get; set; } - public virtual BlogPost Post { get; set; } - - public Guid UserId { get; set; } - - protected BlogPostLike() - { - } - - public BlogPostLike( - Guid id, - Guid postId, - Guid userId, - Guid? tenantId = null) : base(id) - { - PostId = postId; - UserId = userId; - TenantId = tenantId; - } - } -} diff --git a/api/src/Kurs.Platform.Domain/Blog/BlogPostTag.cs b/api/src/Kurs.Platform.Domain/Blog/BlogPostTag.cs deleted file mode 100644 index f98242bd..00000000 --- a/api/src/Kurs.Platform.Domain/Blog/BlogPostTag.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities; -using Volo.Abp.MultiTenancy; - -namespace Kurs.Platform.Blog -{ - public class BlogPostTag : Entity, IMultiTenant - { - public Guid? TenantId { get; set; } - - public Guid PostId { get; set; } - public virtual BlogPost Post { get; set; } - - public string Tag { get; set; } - - protected BlogPostTag() - { - } - - public BlogPostTag( - Guid id, - Guid postId, - string tag, - Guid? tenantId = null) : base(id) - { - PostId = postId; - Tag = tag; - TenantId = tenantId; - } - } -} diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 5cb67c5d..21db349f 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -62,10 +62,6 @@ public class PlatformDbContext : // Blog Entities public DbSet BlogPosts { get; set; } public DbSet BlogCategories { get; set; } - public DbSet BlogComments { get; set; } - public DbSet BlogPostTags { get; set; } - public DbSet BlogPostLikes { get; set; } - public DbSet BlogCommentLikes { get; set; } // Forum Entities public DbSet ForumCategories { get; set; } @@ -443,66 +439,6 @@ public class PlatformDbContext : .OnDelete(DeleteBehavior.Restrict); }); - builder.Entity(b => - { - b.ToTable(PlatformConsts.DbTablePrefix + "BlogComments", PlatformConsts.DbSchema); - b.ConfigureByConvention(); - - b.Property(x => x.Content).IsRequired().HasMaxLength(2048); - - b.HasOne(x => x.Post) - .WithMany(x => x.Comments) - .HasForeignKey(x => x.PostId) - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne(x => x.Parent) - .WithMany(x => x.Replies) - .HasForeignKey(x => x.ParentId) - .OnDelete(DeleteBehavior.Restrict); - }); - - builder.Entity(b => - { - b.ToTable(PlatformConsts.DbTablePrefix + "BlogPostTags", PlatformConsts.DbSchema); - b.ConfigureByConvention(); - - b.Property(x => x.Tag).IsRequired().HasMaxLength(64); - - b.HasIndex(x => new { x.PostId, x.Tag }).IsUnique(); - b.HasIndex(x => x.Tag); - - b.HasOne(x => x.Post) - .WithMany(x => x.Tags) - .HasForeignKey(x => x.PostId) - .OnDelete(DeleteBehavior.Cascade); - }); - - builder.Entity(b => - { - b.ToTable(PlatformConsts.DbTablePrefix + "BlogPostLikes", PlatformConsts.DbSchema); - b.ConfigureByConvention(); - - b.HasIndex(x => new { x.PostId, x.UserId }).IsUnique(); - - b.HasOne(x => x.Post) - .WithMany(x => x.Likes) - .HasForeignKey(x => x.PostId) - .OnDelete(DeleteBehavior.Cascade); - }); - - builder.Entity(b => - { - b.ToTable(PlatformConsts.DbTablePrefix + "BlogCommentLikes", PlatformConsts.DbSchema); - b.ConfigureByConvention(); - - b.HasIndex(x => new { x.CommentId, x.UserId }).IsUnique(); - - b.HasOne(x => x.Comment) - .WithMany(x => x.Likes) - .HasForeignKey(x => x.CommentId) - .OnDelete(DeleteBehavior.Cascade); - }); - // Forum Entity Configurations builder.Entity(b => { diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250619205823_AddBlogForumEntities.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250620094517_AddBlogForumEntities.Designer.cs similarity index 96% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250619205823_AddBlogForumEntities.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250620094517_AddBlogForumEntities.Designer.cs index 529b5d2b..454202aa 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250619205823_AddBlogForumEntities.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250620094517_AddBlogForumEntities.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20250619205823_AddBlogForumEntities")] + [Migration("20250620094517_AddBlogForumEntities")] partial class AddBlogForumEntities { /// @@ -725,102 +725,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PBlogCategories", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogComment", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("AuthorId") - .HasColumnType("uniqueidentifier"); - - b.Property("Content") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("nvarchar(2048)"); - - 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("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - - b.Property("LikeCount") - .HasColumnType("int"); - - b.Property("ParentId") - .HasColumnType("uniqueidentifier"); - - b.Property("PostId") - .HasColumnType("uniqueidentifier"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("PostId"); - - b.ToTable("PBlogComments", (string)null); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogCommentLike", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("CommentId") - .HasColumnType("uniqueidentifier"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - - b.HasKey("Id"); - - b.HasIndex("CommentId", "UserId") - .IsUnique(); - - b.ToTable("PBlogCommentLikes", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => { b.Property("Id") @@ -932,64 +836,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PBlogPosts", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostLike", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("PostId") - .HasColumnType("uniqueidentifier"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - - b.HasKey("Id"); - - b.HasIndex("PostId", "UserId") - .IsUnique(); - - b.ToTable("PBlogPostLikes", (string)null); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostTag", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("PostId") - .HasColumnType("uniqueidentifier"); - - b.Property("Tag") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("Tag"); - - b.HasIndex("PostId", "Tag") - .IsUnique(); - - b.ToTable("PBlogPostTags", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Entities.AiBot", b => { b.Property("Id") @@ -5003,35 +4849,6 @@ namespace Kurs.Platform.Migrations .OnDelete(DeleteBehavior.SetNull); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogComment", b => - { - b.HasOne("Kurs.Platform.Blog.BlogComment", "Parent") - .WithMany("Replies") - .HasForeignKey("ParentId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("Kurs.Platform.Blog.BlogPost", "Post") - .WithMany("Comments") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Parent"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogCommentLike", b => - { - b.HasOne("Kurs.Platform.Blog.BlogComment", "Comment") - .WithMany("Likes") - .HasForeignKey("CommentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Comment"); - }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => { b.HasOne("Kurs.Platform.Blog.BlogCategory", "Category") @@ -5043,28 +4860,6 @@ namespace Kurs.Platform.Migrations b.Navigation("Category"); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostLike", b => - { - b.HasOne("Kurs.Platform.Blog.BlogPost", "Post") - .WithMany("Likes") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostTag", b => - { - b.HasOne("Kurs.Platform.Blog.BlogPost", "Post") - .WithMany("Tags") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.BankAccount", b => { b.HasOne("Kurs.Platform.Entities.Bank", "Bank") @@ -5355,22 +5150,6 @@ namespace Kurs.Platform.Migrations b.Navigation("Posts"); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogComment", b => - { - b.Navigation("Likes"); - - b.Navigation("Replies"); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => - { - b.Navigation("Comments"); - - b.Navigation("Likes"); - - b.Navigation("Tags"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.Country", b => { b.Navigation("States"); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250619205823_AddBlogForumEntities.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250620094517_AddBlogForumEntities.cs similarity index 72% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250619205823_AddBlogForumEntities.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250620094517_AddBlogForumEntities.cs index e12bb246..92a84e87 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250619205823_AddBlogForumEntities.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250620094517_AddBlogForumEntities.cs @@ -148,84 +148,6 @@ namespace Kurs.Platform.Migrations onDelete: ReferentialAction.Restrict); }); - migrationBuilder.CreateTable( - name: "PBlogComments", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - PostId = table.Column(type: "uniqueidentifier", nullable: false), - Content = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: false), - AuthorId = table.Column(type: "uniqueidentifier", nullable: false), - ParentId = table.Column(type: "uniqueidentifier", nullable: true), - LikeCount = table.Column(type: "int", nullable: false), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_PBlogComments", x => x.Id); - table.ForeignKey( - name: "FK_PBlogComments_PBlogComments_ParentId", - column: x => x.ParentId, - principalTable: "PBlogComments", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_PBlogComments_PBlogPosts_PostId", - column: x => x.PostId, - principalTable: "PBlogPosts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "PBlogPostLikes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - PostId = table.Column(type: "uniqueidentifier", nullable: false), - UserId = table.Column(type: "uniqueidentifier", nullable: false), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_PBlogPostLikes", x => x.Id); - table.ForeignKey( - name: "FK_PBlogPostLikes_PBlogPosts_PostId", - column: x => x.PostId, - principalTable: "PBlogPosts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "PBlogPostTags", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - PostId = table.Column(type: "uniqueidentifier", nullable: false), - Tag = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_PBlogPostTags", x => x.Id); - table.ForeignKey( - name: "FK_PBlogPostTags_PBlogPosts_PostId", - column: x => x.PostId, - principalTable: "PBlogPosts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateTable( name: "PForumPosts", columns: table => new @@ -298,28 +220,6 @@ namespace Kurs.Platform.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "PBlogCommentLikes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - CommentId = table.Column(type: "uniqueidentifier", nullable: false), - UserId = table.Column(type: "uniqueidentifier", nullable: false), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_PBlogCommentLikes", x => x.Id); - table.ForeignKey( - name: "FK_PBlogCommentLikes_PBlogComments_CommentId", - column: x => x.CommentId, - principalTable: "PBlogComments", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateTable( name: "PForumPostLikes", columns: table => new @@ -347,28 +247,6 @@ namespace Kurs.Platform.Migrations table: "PBlogCategories", column: "Slug"); - migrationBuilder.CreateIndex( - name: "IX_PBlogCommentLikes_CommentId_UserId", - table: "PBlogCommentLikes", - columns: new[] { "CommentId", "UserId" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_PBlogComments_ParentId", - table: "PBlogComments", - column: "ParentId"); - - migrationBuilder.CreateIndex( - name: "IX_PBlogComments_PostId", - table: "PBlogComments", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_PBlogPostLikes_PostId_UserId", - table: "PBlogPostLikes", - columns: new[] { "PostId", "UserId" }, - unique: true); - migrationBuilder.CreateIndex( name: "IX_PBlogPosts_CategoryId", table: "PBlogPosts", @@ -389,17 +267,6 @@ namespace Kurs.Platform.Migrations table: "PBlogPosts", column: "Slug"); - migrationBuilder.CreateIndex( - name: "IX_PBlogPostTags_PostId_Tag", - table: "PBlogPostTags", - columns: new[] { "PostId", "Tag" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_PBlogPostTags_Tag", - table: "PBlogPostTags", - column: "Tag"); - migrationBuilder.CreateIndex( name: "IX_PForumCategories_DisplayOrder", table: "PForumCategories", @@ -453,13 +320,7 @@ namespace Kurs.Platform.Migrations protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "PBlogCommentLikes"); - - migrationBuilder.DropTable( - name: "PBlogPostLikes"); - - migrationBuilder.DropTable( - name: "PBlogPostTags"); + name: "PBlogPosts"); migrationBuilder.DropTable( name: "PForumPostLikes"); @@ -471,20 +332,14 @@ namespace Kurs.Platform.Migrations name: "PForumTopicTags"); migrationBuilder.DropTable( - name: "PBlogComments"); + name: "PBlogCategories"); migrationBuilder.DropTable( name: "PForumPosts"); - migrationBuilder.DropTable( - name: "PBlogPosts"); - migrationBuilder.DropTable( name: "PForumTopics"); - migrationBuilder.DropTable( - name: "PBlogCategories"); - migrationBuilder.DropTable( name: "PForumCategories"); } diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index 766f8979..78bdd42b 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -722,102 +722,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PBlogCategories", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogComment", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("AuthorId") - .HasColumnType("uniqueidentifier"); - - b.Property("Content") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("nvarchar(2048)"); - - 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("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - - b.Property("LikeCount") - .HasColumnType("int"); - - b.Property("ParentId") - .HasColumnType("uniqueidentifier"); - - b.Property("PostId") - .HasColumnType("uniqueidentifier"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("ParentId"); - - b.HasIndex("PostId"); - - b.ToTable("PBlogComments", (string)null); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogCommentLike", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("CommentId") - .HasColumnType("uniqueidentifier"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - - b.HasKey("Id"); - - b.HasIndex("CommentId", "UserId") - .IsUnique(); - - b.ToTable("PBlogCommentLikes", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => { b.Property("Id") @@ -929,64 +833,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PBlogPosts", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostLike", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("PostId") - .HasColumnType("uniqueidentifier"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - - b.HasKey("Id"); - - b.HasIndex("PostId", "UserId") - .IsUnique(); - - b.ToTable("PBlogPostLikes", (string)null); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostTag", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("PostId") - .HasColumnType("uniqueidentifier"); - - b.Property("Tag") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("Tag"); - - b.HasIndex("PostId", "Tag") - .IsUnique(); - - b.ToTable("PBlogPostTags", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Entities.AiBot", b => { b.Property("Id") @@ -5000,35 +4846,6 @@ namespace Kurs.Platform.Migrations .OnDelete(DeleteBehavior.SetNull); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogComment", b => - { - b.HasOne("Kurs.Platform.Blog.BlogComment", "Parent") - .WithMany("Replies") - .HasForeignKey("ParentId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("Kurs.Platform.Blog.BlogPost", "Post") - .WithMany("Comments") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Parent"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogCommentLike", b => - { - b.HasOne("Kurs.Platform.Blog.BlogComment", "Comment") - .WithMany("Likes") - .HasForeignKey("CommentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Comment"); - }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => { b.HasOne("Kurs.Platform.Blog.BlogCategory", "Category") @@ -5040,28 +4857,6 @@ namespace Kurs.Platform.Migrations b.Navigation("Category"); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostLike", b => - { - b.HasOne("Kurs.Platform.Blog.BlogPost", "Post") - .WithMany("Likes") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPostTag", b => - { - b.HasOne("Kurs.Platform.Blog.BlogPost", "Post") - .WithMany("Tags") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.BankAccount", b => { b.HasOne("Kurs.Platform.Entities.Bank", "Bank") @@ -5352,22 +5147,6 @@ namespace Kurs.Platform.Migrations b.Navigation("Posts"); }); - modelBuilder.Entity("Kurs.Platform.Blog.BlogComment", b => - { - b.Navigation("Likes"); - - b.Navigation("Replies"); - }); - - modelBuilder.Entity("Kurs.Platform.Blog.BlogPost", b => - { - b.Navigation("Comments"); - - b.Navigation("Likes"); - - b.Navigation("Tags"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.Country", b => { b.Navigation("States"); diff --git a/company/src/locales/blogContent.ts b/company/src/locales/blogContent.ts deleted file mode 100644 index dcbb47f7..00000000 --- a/company/src/locales/blogContent.ts +++ /dev/null @@ -1,203 +0,0 @@ -export interface BlogPostContent { - title: string; - excerpt: string; - content: string; - date: string; - category: string; - readTime: string; -} - -export interface BlogPosts { - [key: string]: { - tr: BlogPostContent; - en: BlogPostContent; - image: string; - author: string; - }; -} - -export const blogContent: BlogPosts = { - 'ai-ve-gelecegi': { - tr: { - title: 'blog.posts.ai.title', - excerpt: 'blog.posts.ai.excerpt', - content: `Yapay zeka (YZ), günümüzün en hızlı gelişen ve dönüştürücü teknolojilerinden biridir. Makine öğrenimi, doğal dil işleme ve bilgisayar görüşü gibi alanlardaki ilerlemeler, YZ'nin hayatımızın birçok alanında etkili olmasını sağlamıştır. Akıllı asistanlardan otonom araçlara, tıbbi teşhislerden finansal analizlere kadar geniş bir yelpazede YZ uygulamalarıyla karşılaşıyoruz. - -YZ'nin geleceği parlak görünmekle birlikte, beraberinde önemli etik, sosyal ve ekonomik zorlukları da getiriyor. YZ'nin karar alma süreçlerindeki şeffaflık, algoritmik yanlılık, iş gücü piyasası üzerindeki potansiyel etkileri ve YZ'nin kötüye kullanımı gibi konular, küresel düzeyde dikkatle ele alınması gereken meselelerdir. - -Bu blog yazısında, yapay zekanın mevcut yeteneklerini, farklı sektörlerdeki kullanım alanlarını ve gelecekteki potansiyelini detaylı bir şekilde inceleyeceğiz. Ayrıca, YZ'nin sorumlu bir şekilde geliştirilmesi ve kullanılması için atılması gereken adımları ve bu alandaki güncel tartışmaları ele alarak, yapay zekanın geleceğine dair kapsamlı bir bakış sunacağız.`, - date: 'blog.posts.ai.date', - category: 'blog.categories.technology', - readTime: "5 dk", - }, - en: { - title: 'blog.posts.ai.title', - excerpt: 'blog.posts.ai.excerpt', - content: `Artificial Intelligence (AI) is one of the fastest-growing and most transformative technologies today. Advances in areas such as machine learning, natural language processing, and computer vision have enabled AI to be effective in many areas of our lives. We encounter AI applications in a wide range of fields, from smart assistants to autonomous vehicles, medical diagnostics to financial analysis. - -While the future of AI looks bright, it also brings significant ethical, social, and economic challenges. Issues such as transparency in AI decision-making processes, algorithmic bias, potential impacts on the labor market, and the misuse of AI are matters that need to be carefully addressed globally. - -In this blog post, we will delve into the current capabilities of artificial intelligence, its applications in various sectors, and its future potential. Furthermore, we will discuss the steps that need to be taken for the responsible development and use of AI and the current debates in this field, providing a comprehensive outlook on the future of artificial intelligence.`, - date: 'blog.posts.ai.date', - category: 'blog.categories.technology', - readTime: "5 dk", - }, - image: 'https://images.pexels.com/photos/8386434/pexels-photo-8386434.jpeg?auto=compress&cs=tinysrgb&w=1920', - author: "Ahmet Yılmaz", - }, - 'web-gelistirmede-son-trendler': { - tr: { - title: 'blog.posts.web.title', - excerpt: 'blog.posts.web.excerpt', - content: `Web geliştirme dünyası sürekli bir değişim ve evrim içinde. Her yıl yeni teknolojiler, frameworkler ve yaklaşımlar ortaya çıkıyor, bu da web geliştiricilerinin sürekli öğrenmesini ve adapte olmasını gerektiriyor. 2024 yılı da bu açıdan farklı değil; heyecan verici yeni trendler ve gelişmeler web ekosistemini şekillendiriyor. - -Bu yılın öne çıkan trendlerinden biri Serverless mimarilerin yükselişi. Geliştiricilerin sunucu yönetimiyle uğraşmadan uygulama geliştirmesine olanak tanıyan Serverless, maliyet etkinliği ve ölçeklenebilirlik gibi avantajlar sunuyor. Bir diğer önemli trend ise WebAssembly (Wasm). Web tarayıcılarında yüksek performanslı kod çalıştırmayı mümkün kılan Wasm, oyunlar, video düzenleyiciler ve CAD yazılımları gibi daha karmaşık uygulamaların web'e taşınmasını sağlıyor. - -Mikro ön uçlar da büyük ölçekli web uygulamalarının yönetimini kolaylaştıran bir mimari desen olarak popülerlik kazanıyor. Bu yaklaşım, büyük ön uç projelerini daha küçük, bağımsız parçalara ayırarak farklı ekiplerin aynı proje üzerinde paralel çalışmasına imkan tanıyor. Bu blog yazısında, bu ve benzeri web geliştirme trendlerini daha detaylı inceleyerek, geleceğin web uygulamalarını şekillendiren teknolojilere derinlemesine bir bakış sunacağız.`, - date: 'blog.posts.web.date', - category: 'blog.categories.webdev', - readTime: "7 dk", - }, - en: { - title: 'blog.posts.web.title', - excerpt: 'blog.posts.web.excerpt', - content: `The world of web development is in a constant state of change and evolution. Every year, new technologies, frameworks, and approaches emerge, requiring web developers to continuously learn and adapt. 2024 is no different in this regard; exciting new trends and developments are shaping the web ecosystem. - -One of the prominent trends this year is the rise of Serverless architectures. Enabling developers to build applications without managing servers, Serverless offers advantages such as cost-effectiveness and scalability. Another significant trend is WebAssembly (Wasm). Allowing high-performance code to run in web browsers, Wasm makes it possible to bring more complex applications like games, video editors, and CAD software to the web. - -Micro frontends are also gaining popularity as an architectural pattern that simplifies the management of large-scale web applications. This approach allows breaking down large frontend projects into smaller, independent pieces, enabling different teams to work on the same project in parallel. In this blog post, we will delve deeper into these and similar web development trends, providing an in-depth look at the technologies shaping the future of web applications.`, - date: 'blog.posts.web.date', - category: 'blog.categories.webdev', - readTime: "7 dk", - }, - image: 'https://images.pexels.com/photos/11035471/pexels-photo-11035471.jpeg?auto=compress&cs=tinysrgb&w=1920', - author: "Mehmet Kaya", - }, - 'siber-guvenlik-tehditleri-ve-korunma-yollari': { - tr: { - title: 'blog.posts.security.title', - excerpt: 'blog.posts.security.excerpt', - content: `Dijitalleşmenin hızla artmasıyla birlikte, siber güvenlik tehditlerinin sayısı ve karmaşıklığı da eş zamanlı olarak artmaktadır. Artık sadece büyük şirketler değil, bireyler ve küçük işletmeler de siber saldırganların hedefi haline gelmiştir. Kişisel verilerin çalınması, kimlik avı (phishing) saldırıları, fidye yazılımları (ransomware) ve dağıtılmış hizmet engelleme (DDoS) saldırıları gibi tehditler, hem maddi hem de manevi zararlara yol açabilmektedir. - -Bu tehditlere karşı korunmak, dijital dünyada güvende kalmak için hayati öneme sahiptir. Güçlü ve benzersiz şifreler kullanmak, iki faktörlü kimlik doğrulama yöntemlerini benimsemek ve yazılımlarımızı düzenli olarak güncellemek, alabileceğimiz temel önlemler arasındadır. Ayrıca, bilinmeyen kaynaklardan gelen e-postalara ve linklere karşı dikkatli olmak, halka açık Wi-Fi ağlarında hassas işlemler yapmaktan kaçınmak da önemlidir. - -Bu blog yazısında, güncel siber güvenlik tehditlerini daha detaylı bir şekilde inceleyeceğiz. Her bir tehdit türünün nasıl çalıştığını, potansiyel etkilerini ve bu tehditlere karşı bireysel ve kurumsal düzeyde alınabilecek en etkili korunma yollarını ele alacağız. Siber güvenlik bilincini artırmak ve dijital varlıklarımızı korumak için pratik ipuçları sunarak, daha güvenli bir çevrimiçi deneyim için rehberlik edeceğiz.`, - date: 'blog.posts.security.date', - category: 'blog.categories.security', - readTime: "6 dk", - }, - en: { - title: 'blog.posts.security.title', - excerpt: 'blog.posts.security.excerpt', - content: `With the rapid increase in digitalization, the number and complexity of cyber security threats are also increasing simultaneously. Not only large corporations but also individuals and small businesses have become targets for cyber attackers. Threats such as personal data theft, phishing attacks, ransomware, and distributed denial-of-service (DDoS) attacks can cause both financial and emotional damage. - -Protecting against these threats is vital for staying safe in the digital world. Using strong and unique passwords, adopting two-factor authentication methods, and regularly updating our software are among the basic precautions we can take. Furthermore, it is important to be cautious about emails and links from unknown sources and to avoid performing sensitive transactions on public Wi-Fi networks. - -In this blog post, we will examine current cyber security threats in more detail. We will discuss how each type of threat works, its potential impacts, and the most effective ways to protect against these threats at both individual and organizational levels. By providing practical tips to increase cyber security awareness and protect our digital assets, we will offer guidance for a safer online experience.`, - date: 'blog.posts.security.date', - category: 'blog.categories.security', - readTime: "6 dk", - }, - image: 'https://images.pexels.com/photos/5380642/pexels-photo-5380642.jpeg?auto=compress&cs=tinysrgb&w=1920', - author: "Ayşe Demir", - }, - 'mobil-uygulama-gelistirmede-cross-platform-cozumler': { - tr: { - title: 'blog.posts.mobile.title', - excerpt: 'blog.posts.mobile.excerpt', - content: `Mobil uygulama geliştirme, günümüzün en dinamik ve talep gören yazılım alanlarından biridir. Akıllı telefonların yaygınlaşmasıyla birlikte, işletmeler ve bireyler mobil platformlarda yer almak için sürekli yeni uygulamalar geliştirmektedir. Geleneksel olarak, iOS ve Android gibi farklı mobil işletim sistemleri için ayrı ayrı native uygulamalar geliştirmek gerekiyordu, bu da zaman ve kaynak açısından maliyetli olabiliyordu. - -Ancak son yıllarda, cross-platform (çapraz platform) mobil geliştirme frameworkleri popülerlik kazanmıştır. Bu frameworkler, geliştiricilerin tek bir kod tabanı kullanarak hem iOS hem de Android platformları için uygulama geliştirmesine olanak tanır. Bu yaklaşım, geliştirme sürecini hızlandırır, maliyetleri düşürür ve bakım kolaylığı sağlar. React Native, Flutter ve Xamarin gibi frameworkler, cross-platform geliştirme alanında öne çıkan çözümlerdir. - -Bu blog yazısında, cross-platform mobil geliştirmenin avantajlarını ve dezavantajlarını detaylı bir şekilde inceleyeceğiz. Farklı frameworklerin özelliklerini, performanslarını ve hangi senaryolarda daha uygun olduklarını karşılaştıracağız. Mobil uygulama geliştirme projeniz için en doğru cross-platform çözümü seçmenize yardımcı olacak bilgiler sunarak, geliştirme sürecinizi daha verimli hale getirmeniz için rehberlik edeceğiz.`, - date: 'blog.posts.mobile.date', - category: 'blog.categories.mobile', - readTime: "4 dk", - }, - en: { - title: 'blog.posts.mobile.title', - excerpt: 'blog.posts.mobile.excerpt', - content: `Mobile application development is one of the most dynamic and in-demand software fields today. With the widespread adoption of smartphones, businesses and individuals are constantly developing new applications to have a presence on mobile platforms. Traditionally, it was necessary to develop separate native applications for different mobile operating systems like iOS and Android, which could be costly in terms of time and resources. - -However, in recent years, cross-platform mobile development frameworks have gained popularity. These frameworks allow developers to build applications for both iOS and Android platforms using a single codebase. This approach accelerates the development process, reduces costs, and provides ease of maintenance. Frameworks like React Native, Flutter, and Xamarin are prominent solutions in the field of cross-platform development. - -In this blog post, we will delve into the advantages and disadvantages of cross-platform mobile development in detail. We will compare the features and performance of different frameworks and discuss in which scenarios they are more suitable. By providing information to help you choose the right cross-platform solution for your mobile application development project, we will guide you to make your development process more efficient.`, - date: 'blog.posts.mobile.date', - category: 'blog.categories.mobile', - readTime: "4 dk", - }, - image: 'https://images.pexels.com/photos/13017583/pexels-photo-13017583.jpeg?auto=compress&cs=tinysrgb&w=1920', - author: "Can Öztürk", - }, - 'veritabani-yonetim-sistemleri-karsilastirmasi': { - tr: { - title: 'blog.posts.database.title', - excerpt: 'blog.posts.database.excerpt', - content: `Veritabanları, modern yazılım uygulamalarının kalbidir. Uygulamaların veriyi depolaması, yönetmesi ve erişmesi için güvenilir ve etkili bir veritabanı yönetim sistemi (VTYS) seçimi kritik öneme sahiptir. Piyasada birçok farklı türde VTYS bulunmaktadır ve her birinin kendine özgü avantajları ve dezavantajları vardır. Doğru VTYS seçimi, uygulamanın performansı, ölçeklenebilirliği, güvenliği ve geliştirme süreci üzerinde doğrudan bir etkiye sahiptir. - -İlişkisel veritabanları (RDBMS), veriyi tablolar halinde düzenler ve SQL (Yapısal Sorgu Dili) kullanarak verilere erişim sağlar. MySQL, PostgreSQL, Oracle ve SQL Server gibi sistemler bu kategoriye girer. RDBMS'ler, veri tutarlılığı ve karmaşık sorgular için güçlü yetenekler sunar. Ancak, büyük ölçekli ve yapısal olmayan verilerle çalışırken performans sorunları yaşanabilir. - -NoSQL (Not Only SQL) veritabanları ise daha esnek veri modelleri sunar ve genellikle büyük ölçekli, dağıtık sistemler ve hızlı veri erişimi gerektiren uygulamalar için tercih edilir. MongoDB (belge tabanlı), Cassandra (geniş sütunlu) ve Redis (anahtar-değer) gibi sistemler NoSQL kategorisine örnektir. NoSQL veritabanları, yatay ölçeklenebilirlik ve yüksek erişilebilirlik sağlama konusunda genellikle RDBMS'lerden daha iyidir. Bu blog yazısında, ilişkisel ve NoSQL veritabanı yönetim sistemlerini detaylı bir şekilde karşılaştırarak, farklı kullanım senaryolarına göre hangi VTYS'nin daha uygun olduğunu ele alacağız.`, - date: 'blog.posts.database.date', - readTime: "8 dk", - category: 'blog.categories.database', - }, - en: { - title: 'blog.posts.database.title', - excerpt: 'blog.posts.database.excerpt', - content: `Databases are the heart of modern software applications. Choosing a reliable and effective database management system (DBMS) is crucial for applications to store, manage, and access data. There are many different types of DBMS available in the market, each with its own unique advantages and disadvantages. The right DBMS choice has a direct impact on the application's performance, scalability, security, and development process. - -Relational database management systems (RDBMS) organize data in tables and provide access to data using SQL (Structured Query Language). Systems like MySQL, PostgreSQL, Oracle, and SQL Server fall into this category. RDBMSs offer strong capabilities for data consistency and complex queries. However, performance issues can arise when working with large-scale and unstructured data. - -NoSQL (Not Only SQL) databases, on the other hand, offer more flexible data models and are generally preferred for large-scale, distributed systems and applications requiring fast data access. Systems like MongoDB (document-based), Cassandra (wide-column), and Redis (key-value) are examples of NoSQL databases. NoSQL databases are generally better than RDBMSs at providing horizontal scalability and high availability. In this blog post, we will compare relational and NoSQL database management systems in detail, discussing which DBMS is more suitable for different use cases.`, - date: 'blog.posts.database.date', - readTime: "8 dk", - category: 'blog.categories.database', - }, - image: 'https://images.pexels.com/photos/325229/pexels-photo-325229.jpeg?auto=compress&cs=tinysrgb&w=1920', - author: "Zeynep Yıldız", - }, - 'dijital-pazarlamada-veri-analizi': { - tr: { - title: 'blog.posts.digital.title', - excerpt: 'blog.posts.digital.excerpt', - content: `Dijital pazarlama dünyası, sürekli değişen algoritmalar, yeni platformlar ve gelişen tüketici davranışlarıyla dinamik bir yapıya sahiptir. Bu karmaşık ortamda başarılı olmak için, pazarlamacıların verilere dayalı kararlar alması ve stratejilerini sürekli olarak optimize etmesi gerekmektedir. İşte tam bu noktada veri analizi devreye girer. Dijital pazarlamada veri analizi, kampanyaların performansını ölçmek, müşteri davranışlarını anlamak, hedef kitleyi daha iyi tanımak ve pazarlama yatırımlarının geri dönüşünü (ROI) maksimize etmek için kritik bir araçtır. - -Veri analizi sayesinde, hangi pazarlama kanallarının en etkili olduğunu belirleyebilir, hangi içerik türlerinin daha fazla etkileşim aldığını anlayabilir ve müşteri yolculuğunun farklı aşamalarındaki performans darboğazlarını tespit edebiliriz. Google Analytics, Adobe Analytics gibi web analizi araçları, sosyal medya analiz platformları ve müşteri ilişkileri yönetimi (CRM) sistemleri, dijital pazarlamacılara değerli veriler sunar. Bu verilerin doğru bir şekilde toplanması, temizlenmesi, analiz edilmesi ve yorumlanması, daha bilinçli ve etkili pazarlama stratejileri oluşturmanın temelini oluşturur. - -Bu blog yazısında, dijital pazarlamada veri analizinin neden bu kadar önemli olduğunu detaylı bir şekilde ele alacağız. Kullanılan temel metrikleri (örneğin, dönüşüm oranı, tıklama oranı, müşteri edinme maliyeti), farklı analiz yöntemlerini ve veri görselleştirme tekniklerini inceleyeceğiz. Ayrıca, veri analizinden elde edilen içgörüleri pazarlama stratejilerine nasıl entegre edebileceğinize dair pratik ipuçları sunarak, dijital pazarlama çabalarınızın etkinliğini artırmanız için rehberlik edeceğiz.`, - date: 'blog.posts.digital.date', - readTime: "6 dk", - category: 'blog.categories.digital', - }, - en: { - title: 'blog.posts.digital.title', - excerpt: 'blog.posts.digital.excerpt', - content: `The world of digital marketing is dynamic, with constantly changing algorithms, new platforms, and evolving consumer behavior. To succeed in this complex environment, marketers need to make data-driven decisions and continuously optimize their strategies. This is where data analysis comes into play. In digital marketing, data analysis is a critical tool for measuring campaign performance, understanding customer behavior, getting to know the target audience better, and maximizing the return on marketing investments (ROI). - -Through data analysis, we can determine which marketing channels are most effective, understand which types of content receive more engagement, and identify performance bottlenecks at different stages of the customer journey. Web analytics tools like Google Analytics and Adobe Analytics, social media analytics platforms, and customer relationship management (CRM) systems provide valuable data to digital marketers. The accurate collection, cleaning, analysis, and interpretation of this data form the basis for creating more informed and effective marketing strategies. - -In this blog post, we will delve into why data analysis is so important in digital marketing. We will examine key metrics used (e.g., conversion rate, click-through rate, customer acquisition cost), different analysis methods, and data visualization techniques. Furthermore, we will provide practical tips on how to integrate insights gained from data analysis into your marketing strategies, guiding you to increase the effectiveness of your digital marketing efforts.`, - date: 'blog.posts.digital.date', - readTime: "6 dk", - category: 'blog.categories.digital', - }, - image: 'https://images.pexels.com/photos/7681091/pexels-photo-7681091.jpeg?auto=compress&cs=tinysrgb&w=1920', - author: "Ali Kara", - }, -}; - -// Blog yazılarının listesi (Blog.tsx'te kullanılacak) -export const blogPostsList = Object.keys(blogContent).map(slug => { - const post = blogContent[slug].tr; // Varsayılan olarak Türkçe içeriği kullanıyoruz, dil bağlamına göre değiştirilebilir - return { - slug, - title: post.title, - excerpt: post.excerpt, - image: blogContent[slug].image, // Görsel bilgisi blogContent'ten alındı - author: blogContent[slug].author, // Yazar bilgisi blogContent'ten alındı - date: post.date, - readTime: post.readTime, - category: post.category, - }; -}); diff --git a/company/src/pages/Blog.tsx b/company/src/pages/Blog.tsx index 26084149..22a29a6d 100644 --- a/company/src/pages/Blog.tsx +++ b/company/src/pages/Blog.tsx @@ -30,19 +30,18 @@ const Blog = () => { const [postsData, categoriesData] = await Promise.all([ blogService.getPosts({ page: currentPage, - pageSize: 9, + pageSize: 10, categoryId: selectedCategory, search: searchQuery, }), blogService.getCategories(), ]); - setPosts(postsData.items); + setPosts(postsData.items.filter(a=> a.isPublished)); setTotalPages(postsData.totalPages); - setCategories(categoriesData); + setCategories(categoriesData.filter(a=> a.isActive)); } catch (error) { console.error("Blog verileri yüklenemedi:", error); - // Fallback to static data if API fails setPosts([]); } finally { setLoading(false); diff --git a/company/src/services/api/blog.service.ts b/company/src/services/api/blog.service.ts index 73bbc0bb..14936993 100644 --- a/company/src/services/api/blog.service.ts +++ b/company/src/services/api/blog.service.ts @@ -35,6 +35,7 @@ export interface BlogCategory { slug: string; description?: string; postCount: number; + isActive: boolean; } export interface BlogComment { @@ -75,10 +76,7 @@ export interface BlogListParams { page?: number; pageSize?: number; categoryId?: string; - tag?: string; search?: string; - authorId?: string; - sortBy?: "latest" | "popular" | "trending"; } export interface PaginatedResponse { @@ -150,59 +148,12 @@ class BlogService { return response.data; } - async incrementViewCount(id: string): Promise { - await apiClient.post(`/api/app/blog/posts/${id}/view`); - } - - async likePost(id: string): Promise { - await apiClient.post(`/api/app/blog/posts/${id}/like`); - } - - async unlikePost(id: string): Promise { - await apiClient.delete(`/api/app/blog/posts/${id}/like`); - } - async getCategories(): Promise { const response = await apiClient.get( "/api/app/blog/categories" ); return response.data; } - - async getTags(count = 20): Promise { - const response = await apiClient.get( - `/api/app/blog/tags?count=${count}` - ); - return response.data; - } - - // Opsiyonel - Yorum API'si mevcutsa kullanılır - async getComments(postId: string): Promise { - const response = await apiClient.get( - `/api/app/blog/posts/${postId}/comments` - ); - return response.data; - } - - async createComment(data: CreateCommentRequest): Promise { - const response = await apiClient.post( - "/api/app/blog/comments", - data - ); - return response.data; - } - - async deleteComment(id: string): Promise { - await apiClient.delete(`/api/app/blog/comments/${id}`); - } - - async likeComment(id: string): Promise { - await apiClient.post(`/api/app/blog/comments/${id}/like`); - } - - async unlikeComment(id: string): Promise { - await apiClient.delete(`/api/app/blog/comments/${id}/like`); - } } export const blogService = new BlogService(); diff --git a/company/src/store/authStore.ts b/company/src/store/authStore.ts index 7bbeb40d..0b5a9bc8 100644 --- a/company/src/store/authStore.ts +++ b/company/src/store/authStore.ts @@ -30,14 +30,14 @@ export const useAuthStore = create()( const user = authService.getUser(); const tenantId = authService.getTenantId(); set({ user, isAuthenticated: true, isLoading: false, tenantId }); - toast.success('Giriş başarılı!'); + toast.success('Giriş başarılı!', { position:'top-center' }); } catch (error: any) { set({ isLoading: false }); const errorMessage = error.response?.data?.error_description || error.response?.data?.error?.message || error.response?.data?.message || 'Giriş başarısız!'; - toast.error(errorMessage); + toast.error(errorMessage, { position:'top-center' }); throw error; } }, @@ -47,10 +47,10 @@ export const useAuthStore = create()( try { await authService.register(data); set({ isLoading: false }); - toast.success('Kayıt başarılı! Lütfen giriş yapın.'); + toast.success('Kayıt başarılı! Lütfen giriş yapın.', { position:'top-center' }); } catch (error: any) { set({ isLoading: false }); - toast.error(error.response?.data?.error?.message || 'Kayıt başarısız!'); + toast.error(error.response?.data?.error?.message || 'Kayıt başarısız!', { position:'top-center' }); throw error; } }, @@ -58,7 +58,7 @@ export const useAuthStore = create()( logout: () => { authService.logout(); set({ user: null, isAuthenticated: false, tenantId: null }); - toast.success('Çıkış yapıldı'); + toast.success('Çıkış yapıldı', { position:'top-center' }); }, checkAuth: async () => { diff --git a/ui/dev-dist/sw.js b/ui/dev-dist/sw.js index 13e730ce..cc019ee3 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.6c62okhp6do" + "revision": "0.6hosm5icco8" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/ui/src/constants/route.constant.ts b/ui/src/constants/route.constant.ts index 8cebd683..64c4a585 100644 --- a/ui/src/constants/route.constant.ts +++ b/ui/src/constants/route.constant.ts @@ -36,10 +36,10 @@ export const ROUTES_ENUM = { }, chart: '/admin/chart/edit/:chartCode', blog: { - management: '/admin/blog/management', + management: '/admin/blog', }, forum: { - management: '/admin/forum/management', + management: '/admin/forum', }, }, settings: '/settings', diff --git a/ui/src/services/blog.service.ts b/ui/src/services/blog.service.ts index 1078aa5e..0e250736 100644 --- a/ui/src/services/blog.service.ts +++ b/ui/src/services/blog.service.ts @@ -33,6 +33,9 @@ export interface BlogCategory { slug: string description?: string postCount: number + isActive: boolean + icon: string + displayOrder: number } export interface BlogComment { @@ -54,6 +57,7 @@ export interface BlogComment { export interface CreateUpdateBlogPostDto { title: string + slug: string content: string summary: string categoryId: string diff --git a/ui/src/views/blog/BlogManagement.tsx b/ui/src/views/blog/BlogManagement.tsx index b24f0ec6..c2329962 100644 --- a/ui/src/views/blog/BlogManagement.tsx +++ b/ui/src/views/blog/BlogManagement.tsx @@ -31,19 +31,26 @@ import THead from '@/components/ui/Table/THead' import TBody from '@/components/ui/Table/TBody' import Td from '@/components/ui/Table/Td' import { SelectBoxOption } from '@/shared/types' -import { enumToList } from '@/utils/enumUtils' +import { CheckBox } from 'devextreme-react' +import { Checkbox } from '@/components/ui' const validationSchema = Yup.object().shape({ - title: Yup.string().required('Başlık gereklidir'), - summary: Yup.string().required('Özet gereklidir'), - categoryId: Yup.string().required('Kategori seçiniz'), - content: Yup.string().required('İçerik gereklidir'), + title: Yup.string().required(), + summary: Yup.string().required(), + categoryId: Yup.string().required(), + content: Yup.string(), + tags: Yup.string(), + coverImage: Yup.string(), + isPublished: Yup.bool(), }) const categoryValidationSchema = Yup.object().shape({ - name: Yup.string().required('İsim gereklidir'), - slug: Yup.string().required('Slug gereklidir'), - description: Yup.string().required('Açıklama gereklidir'), + name: Yup.string().required(), + slug: Yup.string().required(), + description: Yup.string(), + icon: Yup.string(), + displayOrder: Yup.number(), + isActive: Yup.bool(), }) const BlogManagement = () => { @@ -79,6 +86,9 @@ const BlogManagement = () => { Veriler yüklenirken hata oluştu , + { + placement: 'top-center', + }, ) } finally { setLoading(false) @@ -102,6 +112,9 @@ const BlogManagement = () => { Blog yazısı silindi , + { + placement: 'top-center', + }, ) loadData() } catch (error) { @@ -109,6 +122,9 @@ const BlogManagement = () => { Silme işlemi başarısız , + { + placement: 'top-center', + }, ) } } @@ -117,6 +133,7 @@ const BlogManagement = () => { try { const data: CreateUpdateBlogPostDto = { title: values.title, + slug: values.slug, content: values.content, summary: values.summary, categoryId: values.categoryId, @@ -131,6 +148,9 @@ const BlogManagement = () => { Blog yazısı güncellendi , + { + placement: 'top-center', + }, ) } else { await blogService.createPost(data) @@ -138,6 +158,9 @@ const BlogManagement = () => { Blog yazısı oluşturuldu , + { + placement: 'top-center', + }, ) } @@ -148,6 +171,9 @@ const BlogManagement = () => { İşlem başarısız , + { + placement: 'top-center', + }, ) } finally { setSubmitting(false) @@ -162,6 +188,9 @@ const BlogManagement = () => { Yayından kaldırıldı , + { + placement: 'top-center', + }, ) } else { await blogService.publishPost(post.id) @@ -169,6 +198,9 @@ const BlogManagement = () => { Yayınlandı , + { + placement: 'top-center', + }, ) } loadData() @@ -177,6 +209,9 @@ const BlogManagement = () => { İşlem başarısız , + { + placement: 'top-center', + }, ) } } @@ -189,6 +224,7 @@ const BlogManagement = () => { const handleEditCategory = (category: BlogCategory) => { setEditingCategory(category) + console.log(category) setCategoryModalVisible(true) } @@ -199,6 +235,9 @@ const BlogManagement = () => { Kategori silindi , + { + placement: 'top-center', + }, ) loadData() } catch (error) { @@ -206,6 +245,9 @@ const BlogManagement = () => { Silme işlemi başarısız , + { + placement: 'top-center', + }, ) } } @@ -227,6 +269,9 @@ const BlogManagement = () => { Kategori güncellendi , + { + placement: 'top-center', + }, ) } else { await blogService.createCategory(data) @@ -234,6 +279,9 @@ const BlogManagement = () => { Kategori oluşturuldu , + { + placement: 'top-center', + }, ) } @@ -244,6 +292,9 @@ const BlogManagement = () => { İşlem başarısız , + { + placement: 'top-center', + }, ) } finally { setSubmitting(false) @@ -253,6 +304,7 @@ const BlogManagement = () => { const initialValues = editingPost ? { title: editingPost.title, + slug: editingPost.slug, summary: editingPost.summary, content: editingPost.content, categoryId: editingPost.category.id, @@ -262,6 +314,7 @@ const BlogManagement = () => { } : { title: '', + slug: '', summary: '', content: '', categoryId: '', @@ -275,9 +328,9 @@ const BlogManagement = () => { name: editingCategory.name, slug: editingCategory.slug, description: editingCategory.description || '', - icon: '', - displayOrder: 0, - isActive: true, + icon: editingCategory.icon, + displayOrder: editingCategory.displayOrder, + isActive: editingCategory.isActive, } : { name: '', @@ -290,19 +343,6 @@ const BlogManagement = () => { return ( <> -
-

Blog Yönetimi

- {activeTab === 'posts' ? ( - - ) : ( - - )} -
-
@@ -322,64 +362,46 @@ const BlogManagement = () => {
{activeTab === 'posts' ? ( - +
+ - - - + + {loading ? ( - + ) : ( posts.map((post) => ( - + + - - +
BaşlıkSlug Kategori YazarDurumGör. / Beğ. / Yorum Yayın TarihiİşlemlerDurum + {' '} + +
Yükleniyor...Yükleniyor...
- navigate(`/blog/${post.slug || post.id}`)} - > - {post.title} - - {post.title}{post.slug} {post.category?.name} {post.author?.name} - - {post.isPublished ? 'Yayında' : 'Taslak'} - - - {post.viewCount} / {post.likeCount} / {post.commentCount} - {post.publishedAt ? format(new Date(post.publishedAt), 'dd MMM yyyy', { locale: tr }) : '-'} + handlePublish(post)} /> +
-
) : ( - +
- + + {loading ? ( - + ) : ( categories.map((category) => ( @@ -417,6 +449,17 @@ const BlogManagement = () => { + {loading ? ( - + ) : ( categories.map((category) => ( @@ -327,7 +363,7 @@ const ForumManagement = () => { {loading ? ( - + ) : ( topics.map((topic) => (
İsim Slug Açıklama Yazı SayısıİşlemlerDurum + +
Yükleniyor...Yükleniyor...
{category.slug} {category.description} {category.postCount} + + {category.isActive ? 'Aktif' : 'Pasif'} + +
Yükleniyor...Yükleniyor...
Yükleniyor...Yükleniyor...