diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/TagEntity.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/TagEntity.cs new file mode 100644 index 00000000..0d3dbdeb --- /dev/null +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/Entities/TagEntity.cs @@ -0,0 +1,11 @@ +using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; + +namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; + +public class TagEntity +{ + [J("name")] public required string Name { get; set; } + [J("url")] public required string Url { get; set; } + [J("following")] public required bool Following { get; set; } + [J("history")] public object? History => null; +} \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/SearchSchemas.cs b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/SearchSchemas.cs index 0e2f7f49..ab36852b 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/Schemas/SearchSchemas.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/Schemas/SearchSchemas.cs @@ -22,6 +22,6 @@ public abstract class SearchSchemas { [J("accounts")] public required List Accounts { get; set; } [J("statuses")] public required List Statuses { get; set; } - [J("hashtags")] public List Hashtags => []; //TODO: implement this + [J("hashtags")] public required List Hashtags { get; set; } } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs b/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs index 8867c8cf..23d36e67 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/SearchController.cs @@ -6,14 +6,17 @@ using Iceshrimp.Backend.Controllers.Mastodon.Attributes; using Iceshrimp.Backend.Controllers.Mastodon.Renderers; using Iceshrimp.Backend.Controllers.Mastodon.Schemas; using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities; +using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Database; using Iceshrimp.Backend.Core.Extensions; +using Iceshrimp.Backend.Core.Helpers; using Iceshrimp.Backend.Core.Middleware; using Iceshrimp.Backend.Core.Services; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; namespace Iceshrimp.Backend.Controllers.Mastodon; @@ -27,7 +30,8 @@ public class SearchController( NoteRenderer noteRenderer, UserRenderer userRenderer, NoteService noteSvc, - ActivityPub.UserResolver userResolver + ActivityPub.UserResolver userResolver, + IOptions config ) : ControllerBase { [HttpGet("/api/v2/search")] @@ -43,8 +47,8 @@ public class SearchController( var result = new SearchSchemas.SearchResponse { Accounts = search.Type is null or "accounts" ? await SearchUsersAsync(search, pagination) : [], - Statuses = search.Type is null or "statuses" ? await SearchNotesAsync(search, pagination) : [] - //TODO: implement hashtags + Statuses = search.Type is null or "statuses" ? await SearchNotesAsync(search, pagination) : [], + Hashtags = search.Type is null or "hashtags" ? await SearchTagsAsync(search, pagination) : [] }; return Ok(result); @@ -188,4 +192,25 @@ public class SearchController( .PrecomputeVisibilities(user) .RenderAllForMastodonAsync(noteRenderer, user); } + + [SuppressMessage("ReSharper", "EntityFramework.UnsupportedServerSideFunctionCall", + Justification = "Inspection doesn't know about the Projectable attribute")] + private async Task> SearchTagsAsync( + SearchSchemas.SearchRequest search, + MastodonPaginationQuery pagination + ) + { + return await db.Hashtags + .Where(p => EF.Functions.ILike(p.Name, "%" + EfHelpers.EscapeLikeQuery(search.Query!) + "%")) + .Paginate(pagination, ControllerContext) + .OrderByDescending(p => p.Id) + .Skip(pagination.Offset ?? 0) + .Select(p => new TagEntity + { + Name = p.Name, + Url = $"https://{config.Value.WebDomain}/tags/{p.Name}", + Following = false, //TODO + }) + .ToListAsync(); + } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs b/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs index 827d0070..21aa847c 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/Hashtag.cs @@ -12,7 +12,7 @@ namespace Iceshrimp.Backend.Core.Database.Tables; [Index("Name", IsUnique = true)] [Index("MentionedRemoteUsersCount")] [Index("AttachedUsersCount")] -public class Hashtag +public class Hashtag : IEntity { [Key] [Column("id")]