160 lines
5.9 KiB
C#
160 lines
5.9 KiB
C#
using DysonNetwork.Shared.Models;
|
|
using DysonNetwork.Shared.Registry;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace DysonNetwork.Sphere.Autocompletion;
|
|
|
|
public class AutocompletionService(AppDatabase db, AccountClientHelper accountsHelper)
|
|
{
|
|
public async Task<List<DysonNetwork.Shared.Models.Autocompletion>> GetAutocompletion(string content, Guid? chatId = null, Guid? realmId = null, int limit = 10)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
return [];
|
|
|
|
if (content.StartsWith('@'))
|
|
{
|
|
var afterAt = content[1..];
|
|
string type;
|
|
string query;
|
|
bool hadSlash = afterAt.Contains('/');
|
|
if (hadSlash)
|
|
{
|
|
var parts = afterAt.Split('/', 2);
|
|
type = parts[0];
|
|
query = parts.Length > 1 ? parts[1] : "";
|
|
}
|
|
else
|
|
{
|
|
type = "u";
|
|
query = afterAt;
|
|
}
|
|
|
|
return await AutocompleteAt(type, query, chatId, realmId, hadSlash, limit);
|
|
}
|
|
|
|
if (!content.StartsWith(':')) return [];
|
|
{
|
|
var query = content[1..];
|
|
return await AutocompleteSticker(query, limit);
|
|
}
|
|
}
|
|
|
|
private async Task<List<DysonNetwork.Shared.Models.Autocompletion>> AutocompleteAt(string type, string query, Guid? chatId, Guid? realmId, bool hadSlash,
|
|
int limit)
|
|
{
|
|
var results = new List<DysonNetwork.Shared.Models.Autocompletion>();
|
|
|
|
switch (type)
|
|
{
|
|
case "u":
|
|
var allAccounts = await accountsHelper.SearchAccounts(query);
|
|
var filteredAccounts = allAccounts;
|
|
|
|
if (chatId.HasValue)
|
|
{
|
|
var chatMemberIds = await db.ChatMembers
|
|
.Where(m => m.ChatRoomId == chatId.Value && m.JoinedAt != null && m.LeaveAt == null)
|
|
.Select(m => m.AccountId)
|
|
.ToListAsync();
|
|
var chatMemberIdStrings = chatMemberIds.Select(id => id.ToString()).ToHashSet();
|
|
filteredAccounts = allAccounts.Where(a => chatMemberIdStrings.Contains(a.Id)).ToList();
|
|
}
|
|
else if (realmId.HasValue)
|
|
{
|
|
var realmMemberIds = await db.RealmMembers
|
|
.Where(m => m.RealmId == realmId.Value && m.LeaveAt == null)
|
|
.Select(m => m.AccountId)
|
|
.ToListAsync();
|
|
var realmMemberIdStrings = realmMemberIds.Select(id => id.ToString()).ToHashSet();
|
|
filteredAccounts = allAccounts.Where(a => realmMemberIdStrings.Contains(a.Id)).ToList();
|
|
}
|
|
|
|
var users = filteredAccounts
|
|
.Take(limit)
|
|
.Select(a => new DysonNetwork.Shared.Models.Autocompletion
|
|
{
|
|
Type = "user",
|
|
Keyword = "@" + (hadSlash ? "u/" : "") + a.Name,
|
|
Data = SnAccount.FromProtoValue(a)
|
|
})
|
|
.ToList();
|
|
results.AddRange(users);
|
|
break;
|
|
case "p":
|
|
var publishers = await db.Publishers
|
|
.Where(p => EF.Functions.Like(p.Name, $"{query}%") || EF.Functions.Like(p.Nick, $"{query}%"))
|
|
.Take(limit)
|
|
.Select(p => new DysonNetwork.Shared.Models.Autocompletion
|
|
{
|
|
Type = "publisher",
|
|
Keyword = "@p/" + p.Name,
|
|
Data = p
|
|
})
|
|
.ToListAsync();
|
|
results.AddRange(publishers);
|
|
break;
|
|
|
|
case "r":
|
|
var realms = await db.Realms
|
|
.Where(r => EF.Functions.Like(r.Slug, $"{query}%") || EF.Functions.Like(r.Name, $"{query}%"))
|
|
.Take(limit)
|
|
.Select(r => new DysonNetwork.Shared.Models.Autocompletion
|
|
{
|
|
Type = "realm",
|
|
Keyword = "@r/" + r.Slug,
|
|
Data = r
|
|
})
|
|
.ToListAsync();
|
|
results.AddRange(realms);
|
|
break;
|
|
|
|
case "c":
|
|
var chats = await db.ChatRooms
|
|
.Where(c => c.Name != null && EF.Functions.Like(c.Name, $"{query}%"))
|
|
.Take(limit)
|
|
.Select(c => new DysonNetwork.Shared.Models.Autocompletion
|
|
{
|
|
Type = "chat",
|
|
Keyword = "@c/" + c.Name,
|
|
Data = c
|
|
})
|
|
.ToListAsync();
|
|
results.AddRange(chats);
|
|
break;
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
private async Task<List<DysonNetwork.Shared.Models.Autocompletion>> AutocompleteSticker(string query, int limit)
|
|
{
|
|
var stickers = await db.Stickers
|
|
.Include(s => s.Pack)
|
|
.Where(s => EF.Functions.Like(s.Slug, $"{query}%"))
|
|
.Take(limit)
|
|
.Select(s => new DysonNetwork.Shared.Models.Autocompletion
|
|
{
|
|
Type = "sticker",
|
|
Keyword = s.Slug,
|
|
Data = s
|
|
})
|
|
.ToListAsync();
|
|
|
|
// Also possibly search by pack prefix? But user said slug after :
|
|
// Perhaps combine or search packs
|
|
var packs = await db.StickerPacks
|
|
.Where(p => EF.Functions.Like(p.Prefix, $"{query}%"))
|
|
.Take(limit)
|
|
.Select(p => new DysonNetwork.Shared.Models.Autocompletion
|
|
{
|
|
Type = "sticker_pack",
|
|
Keyword = p.Prefix,
|
|
Data = p
|
|
})
|
|
.ToListAsync();
|
|
|
|
var results = stickers.Concat(packs).Take(limit).ToList();
|
|
return results;
|
|
}
|
|
}
|