Blog Application Service güncellemeleri
This commit is contained in:
parent
7386ff91fa
commit
d891ae3f85
9 changed files with 426 additions and 340 deletions
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Kurs.Platform.Blog;
|
||||
|
||||
public class BlogPostAndCategoriesDto
|
||||
{
|
||||
public PagedResultDto<BlogPostListDto> Posts { get; set; }
|
||||
public List<BlogCategoryDto> Categories { get; set; }
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ namespace Kurs.Platform.Blog;
|
|||
public interface IBlogAppService : IApplicationService
|
||||
{
|
||||
// Blog Post methods
|
||||
Task<PagedResultDto<BlogPostListDto>> GetPostsAsync(GetBlogPostsInput input);
|
||||
Task<BlogPostAndCategoriesDto> GetPostListAsync(GetBlogPostsInput input);
|
||||
Task<BlogPostDto> GetPostAsync(Guid id);
|
||||
Task<BlogPostDto> GetPostBySlugAsync(string slug);
|
||||
Task<BlogPostDto> CreatePostAsync(CreateUpdateBlogPostDto input);
|
||||
|
|
@ -19,7 +19,7 @@ public interface IBlogAppService : IApplicationService
|
|||
Task<BlogPostDto> UnpublishPostAsync(Guid id);
|
||||
|
||||
// Blog Category methods
|
||||
Task<List<BlogCategoryDto>> GetCategoriesAsync();
|
||||
// Task<List<BlogCategoryDto>> GetCategoriesAsync();
|
||||
Task<BlogCategoryDto> GetCategoryAsync(Guid id);
|
||||
Task<BlogCategoryDto> CreateCategoryAsync(CreateUpdateBlogCategoryDto input);
|
||||
Task<BlogCategoryDto> UpdateCategoryAsync(Guid id, CreateUpdateBlogCategoryDto input);
|
||||
|
|
|
|||
|
|
@ -11,302 +11,370 @@ using Volo.Abp.Domain.Entities;
|
|||
using Volo.Abp.Domain.Repositories;
|
||||
using Volo.Abp.Users;
|
||||
|
||||
namespace Kurs.Platform.Blog
|
||||
namespace Kurs.Platform.Blog;
|
||||
|
||||
[Authorize]
|
||||
public class BlogAppService : PlatformAppService, IBlogAppService
|
||||
{
|
||||
[Authorize]
|
||||
public class BlogAppService : PlatformAppService, IBlogAppService
|
||||
private readonly IRepository<BlogPost, Guid> _postRepository;
|
||||
private readonly IRepository<BlogCategory, Guid> _categoryRepository;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
private readonly IStringLocalizer<PlatformResource> _localizer;
|
||||
|
||||
public BlogAppService(
|
||||
IRepository<BlogPost, Guid> postRepository,
|
||||
IRepository<BlogCategory, Guid> categoryRepository,
|
||||
ICurrentUser currentUser,
|
||||
IStringLocalizer<PlatformResource> localizer)
|
||||
{
|
||||
private readonly IRepository<BlogPost, Guid> _postRepository;
|
||||
private readonly IRepository<BlogCategory, Guid> _categoryRepository;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
private readonly IStringLocalizer<PlatformResource> _localizer;
|
||||
|
||||
public BlogAppService(
|
||||
IRepository<BlogPost, Guid> postRepository,
|
||||
IRepository<BlogCategory, Guid> categoryRepository,
|
||||
ICurrentUser currentUser,
|
||||
IStringLocalizer<PlatformResource> localizer)
|
||||
{
|
||||
_postRepository = postRepository;
|
||||
_categoryRepository = categoryRepository;
|
||||
_currentUser = currentUser;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
// Blog Post methods
|
||||
[AllowAnonymous]
|
||||
public async Task<PagedResultDto<BlogPostListDto>> GetPostsAsync(GetBlogPostsInput input)
|
||||
{
|
||||
var allPosts = await _postRepository.GetListAsync(); // Tüm kayıtlar memory'ye alınır
|
||||
|
||||
var filtered = allPosts.Where(post =>
|
||||
{
|
||||
var searchMatch = string.IsNullOrWhiteSpace(input.Search) ||
|
||||
post.ContentTr.Contains(input.Search, StringComparison.OrdinalIgnoreCase) ||
|
||||
post.ContentEn.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<BlogPost, BlogPostListDto>(post);
|
||||
|
||||
if (categoryDict.TryGetValue(post.CategoryId, out var category))
|
||||
{
|
||||
dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
dto.Author = new AuthorDto
|
||||
{
|
||||
Id = post.AuthorId,
|
||||
Name = "User"
|
||||
};
|
||||
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
return new PagedResultDto<BlogPostListDto>(totalCount, postDtos);
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<BlogPostDto> GetPostAsync(Guid id)
|
||||
{
|
||||
var post = await _postRepository.GetAsync(id);
|
||||
var dto = ObjectMapper.Map<BlogPost, BlogPostDto>(post);
|
||||
|
||||
// Get category
|
||||
dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(
|
||||
await _categoryRepository.GetAsync(post.CategoryId)
|
||||
);
|
||||
|
||||
// Get author info
|
||||
dto.Author = new AuthorDto
|
||||
{
|
||||
Id = post.AuthorId,
|
||||
Name = "User"
|
||||
};
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<BlogPostDto> GetPostBySlugAsync(string slug)
|
||||
{
|
||||
var post = await _postRepository.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
if (post == null)
|
||||
{
|
||||
throw new EntityNotFoundException(typeof(BlogPost));
|
||||
}
|
||||
|
||||
return await GetPostAsync(post.Id);
|
||||
}
|
||||
|
||||
public async Task<BlogPostDto> CreatePostAsync(CreateUpdateBlogPostDto input)
|
||||
{
|
||||
var post = new BlogPost(
|
||||
GuidGenerator.Create(),
|
||||
input.Title,
|
||||
input.Slug,
|
||||
input.ContentTr,
|
||||
input.ContentEn,
|
||||
input.Summary,
|
||||
input.ReadTime,
|
||||
input.CoverImage,
|
||||
input.CategoryId,
|
||||
_currentUser.Id.Value,
|
||||
true,
|
||||
DateTime.UtcNow,
|
||||
(Guid?)CurrentTenant.Id
|
||||
);
|
||||
|
||||
await _postRepository.InsertAsync(post, autoSave: true);
|
||||
|
||||
return await GetPostAsync(post.Id);
|
||||
}
|
||||
|
||||
public async Task<BlogPostDto> UpdatePostAsync(Guid id, CreateUpdateBlogPostDto input)
|
||||
{
|
||||
var post = await _postRepository.GetAsync(id);
|
||||
|
||||
if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.BlogManagement.Update"))
|
||||
{
|
||||
throw new Volo.Abp.Authorization.AbpAuthorizationException();
|
||||
}
|
||||
|
||||
post.Title = input.Title;
|
||||
post.Slug = input.Slug;
|
||||
post.Summary = input.Summary;
|
||||
post.CoverImage = input.CoverImage;
|
||||
post.ContentTr = input.ContentTr;
|
||||
post.ContentEn = input.ContentEn;
|
||||
|
||||
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);
|
||||
|
||||
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.BlogManagement.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<BlogPostDto> 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.BlogManagement.Publish"))
|
||||
{
|
||||
throw new Volo.Abp.Authorization.AbpAuthorizationException();
|
||||
}
|
||||
|
||||
post.Publish();
|
||||
await _postRepository.UpdateAsync(post);
|
||||
|
||||
return await GetPostAsync(id);
|
||||
}
|
||||
|
||||
public async Task<BlogPostDto> 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.BlogManagement.Publish"))
|
||||
{
|
||||
throw new Volo.Abp.Authorization.AbpAuthorizationException();
|
||||
}
|
||||
|
||||
post.Unpublish();
|
||||
await _postRepository.UpdateAsync(post);
|
||||
|
||||
return await GetPostAsync(id);
|
||||
}
|
||||
|
||||
// Blog Category methods
|
||||
[AllowAnonymous]
|
||||
public async Task<List<BlogCategoryDto>> GetCategoriesAsync()
|
||||
{
|
||||
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<BlogCategory>, List<BlogCategoryDto>>(categories);
|
||||
|
||||
foreach (var dto in dtoList)
|
||||
{
|
||||
dto.PostCount = groupedCounts
|
||||
.FirstOrDefault(x => x.CategoryId == dto.Id)?.Count ?? 0;
|
||||
}
|
||||
|
||||
return dtoList;
|
||||
}
|
||||
|
||||
public async Task<BlogCategoryDto> GetCategoryAsync(Guid id)
|
||||
{
|
||||
var category = await _categoryRepository.GetAsync(id);
|
||||
return ObjectMapper.Map<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
[Authorize("App.BlogManagement.Create")]
|
||||
public async Task<BlogCategoryDto> CreateCategoryAsync(CreateUpdateBlogCategoryDto input)
|
||||
{
|
||||
var category = new BlogCategory(
|
||||
GuidGenerator.Create(),
|
||||
input.Name,
|
||||
input.Slug,
|
||||
input.Description,
|
||||
CurrentTenant.Id
|
||||
);
|
||||
|
||||
category.Icon = input.Icon;
|
||||
category.DisplayOrder = input.DisplayOrder;
|
||||
category.IsActive = input.IsActive;
|
||||
|
||||
await _categoryRepository.InsertAsync(category);
|
||||
|
||||
return ObjectMapper.Map<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
[Authorize("App.BlogManagement.Update")]
|
||||
public async Task<BlogCategoryDto> 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<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
[Authorize("App.BlogManagement.Delete")]
|
||||
public async Task DeleteCategoryAsync(Guid id)
|
||||
{
|
||||
// Check if category has posts
|
||||
var hasPost = await _postRepository.AnyAsync(x => x.CategoryId == id);
|
||||
if (hasPost)
|
||||
{
|
||||
throw new Volo.Abp.BusinessException("Cannot delete category with posts");
|
||||
}
|
||||
|
||||
await _categoryRepository.DeleteAsync(id);
|
||||
}
|
||||
|
||||
_postRepository = postRepository;
|
||||
_categoryRepository = categoryRepository;
|
||||
_currentUser = currentUser;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
// Blog Post methods
|
||||
[AllowAnonymous]
|
||||
public async Task<BlogPostAndCategoriesDto> GetPostListAsync(GetBlogPostsInput input)
|
||||
{
|
||||
// IQueryable
|
||||
var postQuery = await _postRepository.GetQueryableAsync();
|
||||
|
||||
// 🔎 Arama
|
||||
if (!input.Search.IsNullOrWhiteSpace())
|
||||
{
|
||||
postQuery = postQuery.Where(p =>
|
||||
p.ContentTr.Contains(input.Search) ||
|
||||
p.ContentEn.Contains(input.Search));
|
||||
}
|
||||
|
||||
// 📁 Kategori filtresi
|
||||
if (input.CategoryId.HasValue)
|
||||
{
|
||||
postQuery = postQuery.Where(p => p.CategoryId == input.CategoryId.Value);
|
||||
}
|
||||
|
||||
// Toplam adet (sayfalama öncesi)
|
||||
var totalCount = await AsyncExecuter.CountAsync(postQuery);
|
||||
|
||||
// Sayfalama + sıralama
|
||||
var pagedPosts = await AsyncExecuter.ToListAsync(
|
||||
postQuery
|
||||
.OrderByDescending(p => p.CreationTime)
|
||||
.PageBy(input)
|
||||
);
|
||||
|
||||
// Sayfadaki kategori kayıtları
|
||||
var categoryIds = pagedPosts.Select(x => x.CategoryId).Distinct().ToList();
|
||||
var pageCategories = await _categoryRepository.GetListAsync(x => categoryIds.Contains(x.Id));
|
||||
var categoryDict = pageCategories.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// Post DTO mapping
|
||||
var postDtos = pagedPosts.Select(post =>
|
||||
{
|
||||
var dto = ObjectMapper.Map<BlogPost, BlogPostListDto>(post);
|
||||
if (categoryDict.TryGetValue(post.CategoryId, out var c))
|
||||
{
|
||||
dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(c);
|
||||
}
|
||||
|
||||
dto.Author = new AuthorDto { Id = post.AuthorId, Name = "User" };
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
// ----------- KATEGORİLER (PostCount ile) -----------
|
||||
var allCategories = await _categoryRepository.GetListAsync();
|
||||
|
||||
var allPostQuery = await _postRepository.GetQueryableAsync();
|
||||
var counts = await AsyncExecuter.ToListAsync(
|
||||
allPostQuery
|
||||
.Where(p => p.IsPublished)
|
||||
.GroupBy(p => p.CategoryId)
|
||||
.Select(g => new { g.Key, Count = g.Count() })
|
||||
);
|
||||
|
||||
var countDict = counts.ToDictionary(x => x.Key, x => x.Count);
|
||||
|
||||
var categoryDtos = ObjectMapper.Map<List<BlogCategory>, List<BlogCategoryDto>>(allCategories);
|
||||
foreach (var dto in categoryDtos)
|
||||
{
|
||||
dto.PostCount = countDict.GetOrDefault(dto.Id);
|
||||
}
|
||||
|
||||
return new BlogPostAndCategoriesDto
|
||||
{
|
||||
Posts = new PagedResultDto<BlogPostListDto>(totalCount, postDtos),
|
||||
Categories = categoryDtos
|
||||
};
|
||||
}
|
||||
|
||||
// public async Task<PagedResultDto<BlogPostListDto>> GetPostsAsync(GetBlogPostsInput input)
|
||||
// {
|
||||
// var allPosts = await _postRepository.GetListAsync(); // Tüm kayıtlar memory'ye alınır
|
||||
// var filtered = allPosts.Where(post =>
|
||||
// {
|
||||
// var searchMatch = string.IsNullOrWhiteSpace(input.Search) ||
|
||||
// post.ContentTr.Contains(input.Search, StringComparison.OrdinalIgnoreCase) ||
|
||||
// post.ContentEn.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<BlogPost, BlogPostListDto>(post);
|
||||
// if (categoryDict.TryGetValue(post.CategoryId, out var category))
|
||||
// {
|
||||
// dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(category);
|
||||
// }
|
||||
|
||||
// dto.Author = new AuthorDto
|
||||
// {
|
||||
// Id = post.AuthorId,
|
||||
// Name = "User"
|
||||
// };
|
||||
|
||||
// return dto;
|
||||
// }).ToList();
|
||||
|
||||
// return new PagedResultDto<BlogPostListDto>(totalCount, postDtos);
|
||||
// }
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<BlogPostDto> GetPostAsync(Guid id)
|
||||
{
|
||||
var post = await _postRepository.GetAsync(id);
|
||||
var dto = ObjectMapper.Map<BlogPost, BlogPostDto>(post);
|
||||
|
||||
// Get category
|
||||
dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(
|
||||
await _categoryRepository.GetAsync(post.CategoryId)
|
||||
);
|
||||
|
||||
// Get author info
|
||||
dto.Author = new AuthorDto
|
||||
{
|
||||
Id = post.AuthorId,
|
||||
Name = "User"
|
||||
};
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<BlogPostDto> GetPostBySlugAsync(string slug)
|
||||
{
|
||||
var post = await _postRepository.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
if (post == null)
|
||||
{
|
||||
throw new EntityNotFoundException(typeof(BlogPost));
|
||||
}
|
||||
|
||||
return await GetPostAsync(post.Id);
|
||||
}
|
||||
|
||||
public async Task<BlogPostDto> CreatePostAsync(CreateUpdateBlogPostDto input)
|
||||
{
|
||||
var post = new BlogPost(
|
||||
GuidGenerator.Create(),
|
||||
input.Title,
|
||||
input.Slug,
|
||||
input.ContentTr,
|
||||
input.ContentEn,
|
||||
input.Summary,
|
||||
input.ReadTime,
|
||||
input.CoverImage,
|
||||
input.CategoryId,
|
||||
_currentUser.Id.Value,
|
||||
true,
|
||||
DateTime.UtcNow,
|
||||
(Guid?)CurrentTenant.Id
|
||||
);
|
||||
|
||||
await _postRepository.InsertAsync(post, autoSave: true);
|
||||
|
||||
return await GetPostAsync(post.Id);
|
||||
}
|
||||
|
||||
public async Task<BlogPostDto> UpdatePostAsync(Guid id, CreateUpdateBlogPostDto input)
|
||||
{
|
||||
var post = await _postRepository.GetAsync(id);
|
||||
|
||||
if (post.AuthorId != _currentUser.Id && !await AuthorizationService.IsGrantedAsync("App.BlogManagement.Update"))
|
||||
{
|
||||
throw new Volo.Abp.Authorization.AbpAuthorizationException();
|
||||
}
|
||||
|
||||
post.Title = input.Title;
|
||||
post.Slug = input.Slug;
|
||||
post.Summary = input.Summary;
|
||||
post.CoverImage = input.CoverImage;
|
||||
post.ContentTr = input.ContentTr;
|
||||
post.ContentEn = input.ContentEn;
|
||||
|
||||
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);
|
||||
|
||||
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.BlogManagement.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<BlogPostDto> 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.BlogManagement.Publish"))
|
||||
{
|
||||
throw new Volo.Abp.Authorization.AbpAuthorizationException();
|
||||
}
|
||||
|
||||
post.Publish();
|
||||
await _postRepository.UpdateAsync(post);
|
||||
|
||||
return await GetPostAsync(id);
|
||||
}
|
||||
|
||||
public async Task<BlogPostDto> 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.BlogManagement.Publish"))
|
||||
{
|
||||
throw new Volo.Abp.Authorization.AbpAuthorizationException();
|
||||
}
|
||||
|
||||
post.Unpublish();
|
||||
await _postRepository.UpdateAsync(post);
|
||||
|
||||
return await GetPostAsync(id);
|
||||
}
|
||||
|
||||
// // Blog Category methods
|
||||
// [AllowAnonymous]
|
||||
// public async Task<List<BlogCategoryDto>> GetCategoriesAsync()
|
||||
// {
|
||||
// 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<BlogCategory>, List<BlogCategoryDto>>(categories);
|
||||
|
||||
// foreach (var dto in dtoList)
|
||||
// {
|
||||
// dto.PostCount = groupedCounts
|
||||
// .FirstOrDefault(x => x.CategoryId == dto.Id)?.Count ?? 0;
|
||||
// }
|
||||
|
||||
// return dtoList;
|
||||
// }
|
||||
|
||||
public async Task<BlogCategoryDto> GetCategoryAsync(Guid id)
|
||||
{
|
||||
var category = await _categoryRepository.GetAsync(id);
|
||||
return ObjectMapper.Map<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
[Authorize("App.BlogManagement.Create")]
|
||||
public async Task<BlogCategoryDto> CreateCategoryAsync(CreateUpdateBlogCategoryDto input)
|
||||
{
|
||||
var category = new BlogCategory(
|
||||
GuidGenerator.Create(),
|
||||
input.Name,
|
||||
input.Slug,
|
||||
input.Description,
|
||||
CurrentTenant.Id
|
||||
);
|
||||
|
||||
category.Icon = input.Icon;
|
||||
category.DisplayOrder = input.DisplayOrder;
|
||||
category.IsActive = input.IsActive;
|
||||
|
||||
await _categoryRepository.InsertAsync(category);
|
||||
|
||||
return ObjectMapper.Map<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
[Authorize("App.BlogManagement.Update")]
|
||||
public async Task<BlogCategoryDto> 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<BlogCategory, BlogCategoryDto>(category);
|
||||
}
|
||||
|
||||
[Authorize("App.BlogManagement.Delete")]
|
||||
public async Task DeleteCategoryAsync(Guid id)
|
||||
{
|
||||
// Check if category has posts
|
||||
var hasPost = await _postRepository.AnyAsync(x => x.CategoryId == id);
|
||||
if (hasPost)
|
||||
{
|
||||
throw new Volo.Abp.BusinessException("Cannot delete category with posts");
|
||||
}
|
||||
|
||||
await _categoryRepository.DeleteAsync(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class Program
|
|||
case DatabaseProvider.PostgreSql:
|
||||
loggerConfig = loggerConfig.WriteTo.PostgreSQL(
|
||||
connectionString: configuration.GetConnectionString(DefaultDatabaseProvider),
|
||||
tableName: PlatformConsts.DbTablePrefix + "LogEntry",
|
||||
tableName: PlatformConsts.SelectCommandByTableName("LogEntry"),
|
||||
columnOptions: columnWriters,
|
||||
needAutoCreateTable: true,
|
||||
respectCase: true
|
||||
|
|
@ -52,7 +52,7 @@ public class Program
|
|||
case DatabaseProvider.SqlServer:
|
||||
loggerConfig = loggerConfig.WriteTo.MSSqlServer(
|
||||
connectionString: configuration.GetConnectionString(DefaultDatabaseProvider),
|
||||
tableName: PlatformConsts.DbTablePrefix + "LogEntry",
|
||||
tableName: PlatformConsts.SelectCommandByTableName("LogEntry"),
|
||||
autoCreateSqlTable: true,
|
||||
columnOptions: new Serilog.Sinks.MSSqlServer.ColumnOptions()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
|
|||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||
}, {
|
||||
"url": "index.html",
|
||||
"revision": "0.vah6gtb83uo"
|
||||
"revision": "0.3u9qv452np"
|
||||
}], {});
|
||||
workbox.cleanupOutdatedCaches();
|
||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { PagedResultDto } from '../abp'
|
||||
|
||||
export interface BlogPost {
|
||||
id: string
|
||||
title: string
|
||||
|
|
@ -39,6 +41,11 @@ export interface BlogCategory {
|
|||
tenantId?: string
|
||||
}
|
||||
|
||||
export interface BlogPostAndCategoriesDto {
|
||||
posts: PagedResultDto<BlogPost>
|
||||
categories: BlogCategory[]
|
||||
}
|
||||
|
||||
export interface CreateUpdateBlogPostDto {
|
||||
title: string
|
||||
slug: string
|
||||
|
|
@ -71,11 +78,3 @@ export interface BlogListParams {
|
|||
authorId?: string
|
||||
sortBy?: 'latest' | 'popular' | 'trending'
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
items: T[]
|
||||
totalCount: number
|
||||
pageNumber: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
|
|
@ -1,10 +1,17 @@
|
|||
import { BlogCategory, BlogListParams, BlogPost, CreateUpdateBlogCategoryDto, CreateUpdateBlogPostDto, PaginatedResponse } from '@/proxy/blog/blog';
|
||||
import {
|
||||
BlogCategory,
|
||||
BlogListParams,
|
||||
BlogPost,
|
||||
BlogPostAndCategoriesDto,
|
||||
CreateUpdateBlogCategoryDto,
|
||||
CreateUpdateBlogPostDto,
|
||||
} from '@/proxy/blog/blog'
|
||||
import apiService from '@/services/api.service'
|
||||
|
||||
class BlogService {
|
||||
async getPosts(params: BlogListParams = {}): Promise<PaginatedResponse<BlogPost>> {
|
||||
const response = await apiService.fetchData<PaginatedResponse<BlogPost>>({
|
||||
url: '/api/app/blog/posts',
|
||||
async getPosts(params: BlogListParams = {}): Promise<BlogPostAndCategoriesDto> {
|
||||
const response = await apiService.fetchData<BlogPostAndCategoriesDto>({
|
||||
url: '/api/app/blog/post-list',
|
||||
method: 'GET',
|
||||
params,
|
||||
})
|
||||
|
|
@ -13,10 +20,10 @@ class BlogService {
|
|||
|
||||
async getPostBySlug(slug: string): Promise<BlogPost> {
|
||||
const response = await apiService.fetchData<BlogPost>({
|
||||
url : `/api/app/blog/post-by-slug?slug=${slug}`,
|
||||
url: `/api/app/blog/post-by-slug?slug=${slug}`,
|
||||
method: 'GET',
|
||||
})
|
||||
return response.data;
|
||||
return response.data
|
||||
}
|
||||
|
||||
async getPost(idOrSlug: string): Promise<BlogPost> {
|
||||
|
|
@ -68,13 +75,13 @@ class BlogService {
|
|||
return response.data
|
||||
}
|
||||
|
||||
async getCategories(): Promise<BlogCategory[]> {
|
||||
const response = await apiService.fetchData<BlogCategory[]>({
|
||||
url: '/api/app/blog/categories',
|
||||
method: 'GET',
|
||||
})
|
||||
return response.data
|
||||
}
|
||||
// async getCategories(): Promise<BlogCategory[]> {
|
||||
// const response = await apiService.fetchData<BlogCategory[]>({
|
||||
// url: '/api/app/blog/categories',
|
||||
// method: 'GET',
|
||||
// })
|
||||
// return response.data
|
||||
// }
|
||||
|
||||
async deleteComment(id: string): Promise<void> {
|
||||
await apiService.fetchData({
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import {
|
||||
FaCalendarAlt,
|
||||
FaUser,
|
||||
FaTag,
|
||||
FaSearch
|
||||
} from 'react-icons/fa';
|
||||
import { FaCalendarAlt, FaUser, FaTag, FaSearch } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/tr'
|
||||
import { BlogCategory, BlogPost } from '@/proxy/blog/blog'
|
||||
|
|
@ -33,19 +28,24 @@ const Blog = () => {
|
|||
const loadBlogData = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const [postsData, categoriesData] = await Promise.all([
|
||||
blogService.getPosts({
|
||||
page: currentPage,
|
||||
pageSize: 10,
|
||||
categoryId: selectedCategory,
|
||||
search: searchQuery,
|
||||
}),
|
||||
blogService.getCategories(),
|
||||
])
|
||||
|
||||
setPosts(postsData.items.filter((a) => a.isPublished))
|
||||
setTotalPages(postsData.totalPages)
|
||||
setCategories(categoriesData.filter((a) => a.isActive))
|
||||
const postsData = await blogService.getPosts({
|
||||
page: currentPage,
|
||||
pageSize: 10,
|
||||
categoryId: selectedCategory,
|
||||
search: searchQuery,
|
||||
})
|
||||
|
||||
if (
|
||||
postsData.posts &&
|
||||
postsData.posts.items &&
|
||||
postsData.posts.totalCount &&
|
||||
postsData.categories
|
||||
) {
|
||||
setPosts(postsData.posts.items.filter((a) => a.isPublished))
|
||||
setTotalPages(postsData.posts.totalCount / 10)
|
||||
setCategories(postsData.categories.filter((a) => a.isActive))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Blog verileri yüklenemedi:', error)
|
||||
setPosts([])
|
||||
|
|
|
|||
|
|
@ -116,7 +116,9 @@ const BlogDetail: React.FC = () => {
|
|||
className="prose max-w-none text-gray-800"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
currentLang == 'tr' ? translate(blogPost.contentTr!) : translate(blogPost.contentEn!),
|
||||
currentLang == 'tr'
|
||||
? translate('::' + blogPost.contentTr!)
|
||||
: translate('::' + blogPost.contentEn!),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue