Add chat bulk actions and avatar cache
This commit is contained in:
@@ -121,6 +121,86 @@ public sealed class ChatsController(
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpPost("clear-history")]
|
||||
public async Task<IActionResult> ClearHistories(ChatBulkActionRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
var chatIds = request.ChatIds.Distinct().ToArray();
|
||||
if (chatIds.Length == 0)
|
||||
{
|
||||
return BadRequest("chatIds are required.");
|
||||
}
|
||||
|
||||
var chats = await LoadChatsWithAttachmentsAsync(chatIds, cancellationToken);
|
||||
if (chats.Count != chatIds.Length)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
foreach (var chat in chats)
|
||||
{
|
||||
var maxFailure = await TryApplyMaxChatActionAsync(
|
||||
chat,
|
||||
(externalChatId, chatUrl) => maxBridge.ClearChatHistoryAsync(externalChatId, chatUrl, cancellationToken),
|
||||
"clear history",
|
||||
cancellationToken);
|
||||
if (maxFailure is not null)
|
||||
{
|
||||
return maxFailure;
|
||||
}
|
||||
}
|
||||
|
||||
var files = AttachmentFiles(chats).ToArray();
|
||||
foreach (var chat in chats)
|
||||
{
|
||||
db.Messages.RemoveRange(chat.Messages);
|
||||
chat.LastMessageAt = null;
|
||||
chat.LastMessagePreview = null;
|
||||
chat.UnreadCount = 0;
|
||||
chat.UpdatedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
DeleteFiles(files);
|
||||
await hubContext.Clients.All.SendAsync("ChatListInvalidated", cancellationToken);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpPost("delete")]
|
||||
public async Task<IActionResult> DeleteChats(ChatBulkActionRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
var chatIds = request.ChatIds.Distinct().ToArray();
|
||||
if (chatIds.Length == 0)
|
||||
{
|
||||
return BadRequest("chatIds are required.");
|
||||
}
|
||||
|
||||
var chats = await LoadChatsWithAttachmentsAsync(chatIds, cancellationToken);
|
||||
if (chats.Count != chatIds.Length)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
foreach (var chat in chats)
|
||||
{
|
||||
var maxFailure = await TryApplyMaxChatActionAsync(
|
||||
chat,
|
||||
(externalChatId, chatUrl) => maxBridge.DeleteChatAsync(externalChatId, chatUrl, cancellationToken),
|
||||
"delete chat",
|
||||
cancellationToken);
|
||||
if (maxFailure is not null)
|
||||
{
|
||||
return maxFailure;
|
||||
}
|
||||
}
|
||||
|
||||
var files = AttachmentFiles(chats).ToArray();
|
||||
db.Chats.RemoveRange(chats);
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
DeleteFiles(files);
|
||||
await hubContext.Clients.All.SendAsync("ChatListInvalidated", cancellationToken);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpGet("{chatId:guid}/search")]
|
||||
public async Task<ActionResult<IReadOnlyList<MessageDto>>> SearchMessages(
|
||||
Guid chatId,
|
||||
@@ -656,6 +736,56 @@ public sealed class ChatsController(
|
||||
statusCode: StatusCodes.Status409Conflict);
|
||||
}
|
||||
|
||||
private async Task<ActionResult?> TryApplyMaxChatActionAsync(
|
||||
Chat chat,
|
||||
Func<string, string?, Task<MaxActionResult>> action,
|
||||
string actionName,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(chat.ExternalId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = await action(chat.ExternalId, chat.WebUrl);
|
||||
if (result.Success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Problem(
|
||||
result.Error ?? $"MAX {actionName} action failed for {chat.Title}.",
|
||||
statusCode: StatusCodes.Status409Conflict);
|
||||
}
|
||||
|
||||
private async Task<List<Chat>> LoadChatsWithAttachmentsAsync(IReadOnlyCollection<Guid> chatIds, CancellationToken cancellationToken)
|
||||
{
|
||||
return await db.Chats
|
||||
.Include(x => x.Messages)
|
||||
.ThenInclude(x => x.Attachments)
|
||||
.Where(x => chatIds.Contains(x.Id))
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private IEnumerable<string> AttachmentFiles(IEnumerable<Chat> chats)
|
||||
{
|
||||
return chats
|
||||
.SelectMany(x => x.Messages)
|
||||
.SelectMany(x => x.Attachments)
|
||||
.Select(x => storage.GetPath(x.StorageFileName))
|
||||
.Where(System.IO.File.Exists);
|
||||
}
|
||||
|
||||
private static void DeleteFiles(IEnumerable<string> files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
System.IO.File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static string? NormalizeReaction(string? value)
|
||||
{
|
||||
var emoji = value?.Trim();
|
||||
|
||||
Reference in New Issue
Block a user