Add filtering by tags
This commit is contained in:
@@ -259,9 +259,9 @@ public class PostController(
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<PagedList<PostDto>>> GetAll([Range(1, int.MaxValue)] int pageNumber = 1)
|
||||
public async Task<ActionResult<PagedList<PostDto>>> GetAll(string? query, [Range(1, int.MaxValue)] int pageNumber = 1)
|
||||
{
|
||||
var list = await postService.GetAll(pageNumber);
|
||||
var list = await postService.FindAll(query, pageNumber);
|
||||
var newItems = list.Items.Select(i =>
|
||||
{
|
||||
var fileUrl = Url.Action(nameof(PatchFileContent), "Post",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using T120B165_ImgBoard.Data;
|
||||
using T120B165_ImgBoard.Models;
|
||||
@@ -13,6 +14,7 @@ public interface IPostService
|
||||
string fileName, string fileContentType, long fileSize);
|
||||
Task<Post?> GetById(int postId, bool includeUnfinished = false);
|
||||
Task<PagedList<Post>> GetAll(int pageNumber = 1);
|
||||
public Task<PagedList<Post>> FindAll(string? query, int pageNumber = 1);
|
||||
Task<bool> Delete(Post post);
|
||||
Task<Post> Update(Post post);
|
||||
}
|
||||
@@ -84,6 +86,70 @@ public class PostService(ImgBoardContext context): IPostService
|
||||
return new PagedList<Post>(items, pageNumber, PageSize, totalCount);
|
||||
}
|
||||
|
||||
public async Task<PagedList<Post>> FindAll(string? query, int pageNumber = 1)
|
||||
{
|
||||
var postsQuery = context.Posts
|
||||
.Where(p => p.File.FinishedDate != null);
|
||||
|
||||
// Apply query filtering if the query string is not null or empty
|
||||
if (!string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
// Parse the query string into required and excluded tags
|
||||
var (requiredTags, excludedTags) = ParseTagQuery(query);
|
||||
|
||||
// Filter for required tags (Post must have ALL of these tags)
|
||||
foreach (var requiredTag in requiredTags)
|
||||
{
|
||||
// Where the post's Tags collection contains ANY tag whose name matches the requiredTag.
|
||||
postsQuery = postsQuery.Where(p => p.Tags.Any(t => t.Name == requiredTag));
|
||||
}
|
||||
|
||||
// Filter out excluded tags (Post must NOT have ANY of these tags)
|
||||
foreach (var excludedTag in excludedTags)
|
||||
{
|
||||
// Where the post's Tags collection does NOT contain ANY tag whose name matches the excludedTag.
|
||||
postsQuery = postsQuery.Where(p => p.Tags.All(t => t.Name != excludedTag));
|
||||
}
|
||||
}
|
||||
|
||||
var totalCount = await postsQuery.CountAsync();
|
||||
var items = await postsQuery
|
||||
.Skip((pageNumber - 1) * PageSize)
|
||||
.Take(PageSize)
|
||||
.Include(b => b.Author)
|
||||
.Include(b => b.Tags)
|
||||
.Include(b => b.File)
|
||||
.ToListAsync();
|
||||
return new PagedList<Post>(items, pageNumber, PageSize, totalCount);
|
||||
}
|
||||
|
||||
private static (List<string> requiredTags, List<string> excludedTags) ParseTagQuery(string query)
|
||||
{
|
||||
var requiredTags = new List<string>();
|
||||
var excludedTags = new List<string>();
|
||||
|
||||
// Regex to find all "+tag" or "-tag" segments
|
||||
var matches = Regex.Matches(query, @"([+-])([\w-]+)");
|
||||
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
var type = match.Groups[1].Value; // "+" or "-"
|
||||
var tag = match.Groups[2].Value; // The tag name
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "+":
|
||||
requiredTags.Add(tag);
|
||||
break;
|
||||
case "-":
|
||||
excludedTags.Add(tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (requiredTags, excludedTags);
|
||||
}
|
||||
|
||||
public async Task<bool> Delete(Post post)
|
||||
{
|
||||
context.Posts.Remove(post);
|
||||
|
||||
Reference in New Issue
Block a user