using PrivaPub.Api.Mastodon.Entities; using PrivaPub.Federation.Actors; using PrivaPub.StaticServices; namespace PrivaPub.Api.Mastodon.Mappers { public class AccountSearch { readonly MastodonMapper _mapper; readonly DbEntities _dbEntities; readonly ILocalActorService _localActors; readonly IRemoteActorService _remoteActors; public AccountSearch(MastodonMapper mapper, DbEntities dbEntities, ILocalActorService localActors, IRemoteActorService remoteActors) { _mapper = mapper; _dbEntities = dbEntities; _localActors = localActors; _remoteActors = remoteActors; } public async Task> Find(string q, bool resolve, int limit, CancellationToken token) { q = q?.Trim().TrimStart('@'); if (string.IsNullOrEmpty(q)) return new List(); var results = new List(); var parts = q.Split('@'); var localDomain = new Uri(_localActors.BaseAddress).Authority; if (parts.Length == 2 && !parts[1].Equals(localDomain, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(parts[0])) { var userName = parts[0]; var domain = parts[1].ToLowerInvariant(); var known = await _dbEntities.ForeignAvatars.Match(f => f.UserName == userName && f.Domain == domain).ExecuteFirstAsync(token); if (known == default && resolve) { var actorUri = await _remoteActors.ResolveHandle(q, token); known = actorUri == default ? default : await _remoteActors.GetActor(actorUri, refresh: false, token); } if (known != default) results.Add(_mapper.Foreign(known)); return results; } var prefix = parts[0].ToLowerInvariant(); foreach (var avatar in await _dbEntities.Avatars.Match(a => a.UserName.StartsWith(prefix) && !a.DeletionAt.HasValue && a.Settings.IsDiscoverable != false) .Limit(limit).ExecuteAsync(token)) results.Add(await _mapper.Local(_localActors.FromAvatar(avatar), false, token)); foreach (var foreign in await _dbEntities.ForeignAvatars.Match(f => f.UserName.StartsWith(parts[0]) && f.IsDiscoverable) .Limit(Math.Max(0, limit - results.Count)).ExecuteAsync(token)) results.Add(_mapper.Foreign(foreign)); return results; } } }