using Ikar.Server.Data.Entities; using Ikar.Shared; using Microsoft.EntityFrameworkCore; namespace Ikar.Server.Infrastructure.Admin; public sealed record AdminPage(IReadOnlyList Items, int Total, int Page, int PageSize); public sealed partial class AdminService { private static IQueryable FilterUsers(IQueryable query, string? status) => status switch { "blocked" => query.Where(x => x.IsBlocked), "active" => query.Where(x => !x.IsBlocked), "bots" => query.Where(x => x.IsBot), "people" => query.Where(x => !x.IsBot), _ => query }; public async Task> UserPageAsync(string? q, string? status, int page, int size, CancellationToken ct) { page = Math.Clamp(page, 1, 1000000); size = Math.Clamp(size, 1, 100); var query = FilterUsers(dbContext.Users.AsNoTracking(), status); if (!string.IsNullOrWhiteSpace(q)) { var normalized = q.Trim().ToUpperInvariant(); var like = $"%{q.Trim()}%"; query = query.Where(x => x.NormalizedUsername.Contains(normalized) || EF.Functions.Like(x.DisplayName, like) || x.PhoneNumber != null && EF.Functions.Like(x.PhoneNumber, like)); } return new(await GetUsersAsync(q, ct, page, size, status), await query.CountAsync(ct), page, size); } private static IQueryable FilterChatAttention(IQueryable query, string? attention) => attention switch { "pending" => query.Where(x => x.JoinRequests.Any(r => r.Status == ChatJoinRequestStatus.Pending)), "protected" => query.Where(x => x.HasProtectedContent || x.Messages.Any(m => m.HasProtectedContent)), "topics" => query.Where(x => x.TopicsEnabled || x.Topics.Any()), _ => query }; public async Task> ChatPageAsync(string? q, string? type, int page, int size, CancellationToken ct, string? attention = null) { page = Math.Clamp(page, 1, 1000000); size = Math.Clamp(size, 1, 100); var query = BuildChatsQuery(q); if (Enum.TryParse(type, true, out var kind)) query = query.Where(x => x.Type == kind); query = FilterChatAttention(query, attention); return new(await GetChatsAsync(q, ct, page, size, type, attention), await query.CountAsync(ct), page, size); } public async Task> AttachmentPageAsync(string? q, int page, int size, CancellationToken ct) { page = Math.Clamp(page, 1, 1000000); size = Math.Clamp(size, 1, 100); var query = dbContext.MessageAttachments.AsNoTracking(); if (!string.IsNullOrWhiteSpace(q)) { var like = $"%{q.Trim()}%"; query = query.Where(x => EF.Functions.Like(x.OriginalFileName, like) || EF.Functions.Like(x.ContentType, like) || EF.Functions.Like(x.Message.Sender.DisplayName, like) || x.Message.Chat.Title != null && EF.Functions.Like(x.Message.Chat.Title, like)); } return new(await GetAttachmentsAsync(q, ct, page, size), await query.CountAsync(ct), page, size); } }