145 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using DysonNetwork.Shared.Models;
 | |
| using DysonNetwork.Shared.Registry;
 | |
| using Microsoft.EntityFrameworkCore;
 | |
| 
 | |
| namespace DysonNetwork.Sphere.Autocompletion;
 | |
| 
 | |
| public class AutocompletionService(AppDatabase db, RemoteAccountService remoteAccountsHelper, RemoteRealmService remoteRealmService)
 | |
| {
 | |
|     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;
 | |
|             var 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 remoteAccountsHelper.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)
 | |
|                 {
 | |
|                     // TODO: Filter to realm members only - needs efficient implementation
 | |
|                     // 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 remoteRealmService.SearchRealms(query, limit);
 | |
|                 var autocompletions = realms.Select(r => new DysonNetwork.Shared.Models.Autocompletion
 | |
|                 {
 | |
|                     Type = "realm",
 | |
|                     Keyword = "@r/" + r.Slug,
 | |
|                     Data = r
 | |
|                 });
 | |
|                 results.AddRange(autocompletions);
 | |
|                 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.Pack.Prefix + "+" + s.Slug, $"{query}%"))
 | |
|             .Take(limit)
 | |
|             .Select(s => new DysonNetwork.Shared.Models.Autocompletion
 | |
|             {
 | |
|                 Type = "sticker",
 | |
|                 Keyword = $":{s.Pack.Prefix}+{s.Slug}:",
 | |
|                 Data = s
 | |
|             })
 | |
|             .ToListAsync();
 | |
| 
 | |
|         var results = stickers.ToList();
 | |
|         return results;
 | |
|     }
 | |
| }
 |