[backend/api] Fix race condition causing simultaneous DbContext access in NotificationRenderer
This commit is contained in:
parent
90f1e30ef2
commit
90a6b06410
2 changed files with 38 additions and 19 deletions
|
@ -3,32 +3,27 @@ using Iceshrimp.Backend.Core.Database.Tables;
|
|||
using Iceshrimp.Backend.Core.Extensions;
|
||||
using Iceshrimp.Shared.Schemas.Web;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static Iceshrimp.Shared.Schemas.Web.NotificationResponse;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Web.Renderers;
|
||||
|
||||
public class NotificationRenderer(
|
||||
UserRenderer userRenderer,
|
||||
NoteRenderer noteRenderer,
|
||||
DatabaseContext db
|
||||
)
|
||||
public class NotificationRenderer(UserRenderer userRenderer, NoteRenderer noteRenderer)
|
||||
{
|
||||
public async Task<NotificationResponse> RenderOne(
|
||||
Notification notification, User localUser, NotificationRendererDto? data = null
|
||||
)
|
||||
private static NotificationResponse Render(Notification notification, NotificationRendererDto data)
|
||||
{
|
||||
var user = notification.Notifier != null
|
||||
? (data?.Users ?? await GetUsers([notification])).First(p => p.Id == notification.Notifier.Id)
|
||||
? data.Users?.First(p => p.Id == notification.Notifier.Id) ??
|
||||
throw new Exception("DTO didn't contain the notifier")
|
||||
: null;
|
||||
|
||||
var note = notification.Note != null
|
||||
? (data?.Notes ?? await GetNotes([notification], localUser)).First(p => p.Id == notification.Note.Id)
|
||||
? data.Notes?.First(p => p.Id == notification.Note.Id) ??
|
||||
throw new Exception("DTO didn't contain the note")
|
||||
: null;
|
||||
|
||||
var dbBite = notification.BiteId != null
|
||||
? await db.Bites.FirstOrDefaultAsync(p => p.Id == notification.BiteId)
|
||||
: null;
|
||||
var bite = dbBite != null
|
||||
? new NotificationResponse.BiteResponse { Id = dbBite.Id, BiteBack = dbBite.TargetBiteId != null }
|
||||
var bite = notification.Bite != null
|
||||
? data.Bites?.First(p => p.Id == notification.Bite.Id) ??
|
||||
throw new Exception("DTO didn't contain the bite")
|
||||
: null;
|
||||
|
||||
return new NotificationResponse
|
||||
|
@ -43,6 +38,20 @@ public class NotificationRenderer(
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<NotificationResponse> RenderOne(
|
||||
Notification notification, User localUser
|
||||
)
|
||||
{
|
||||
var data = new NotificationRendererDto
|
||||
{
|
||||
Users = await GetUsers([notification]),
|
||||
Notes = await GetNotes([notification], localUser),
|
||||
Bites = GetBites([notification])
|
||||
};
|
||||
|
||||
return Render(notification, data);
|
||||
}
|
||||
|
||||
private static string RenderType(Notification.NotificationType type) => type switch
|
||||
{
|
||||
Notification.NotificationType.Follow => "follow",
|
||||
|
@ -76,20 +85,29 @@ public class NotificationRenderer(
|
|||
return await noteRenderer.RenderMany(notes, user, Filter.FilterContext.Notifications).ToListAsync();
|
||||
}
|
||||
|
||||
private static List<BiteResponse> GetBites(IEnumerable<Notification> notifications)
|
||||
{
|
||||
var bites = notifications.Select(p => p.Bite).NotNull().DistinctBy(p => p.Id);
|
||||
return bites.Select(p => new BiteResponse { Id = p.Id, BiteBack = p.TargetBiteId != null }).ToList();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<NotificationResponse>> RenderMany(IEnumerable<Notification> notifications, User user)
|
||||
{
|
||||
var notificationsList = notifications.ToList();
|
||||
var data = new NotificationRendererDto
|
||||
{
|
||||
Users = await GetUsers(notificationsList), Notes = await GetNotes(notificationsList, user)
|
||||
Users = await GetUsers(notificationsList),
|
||||
Notes = await GetNotes(notificationsList, user),
|
||||
Bites = GetBites(notificationsList)
|
||||
};
|
||||
|
||||
return await notificationsList.Select(p => RenderOne(p, user, data)).AwaitAllAsync();
|
||||
return notificationsList.Select(p => Render(p, data));
|
||||
}
|
||||
|
||||
public class NotificationRendererDto
|
||||
private class NotificationRendererDto
|
||||
{
|
||||
public List<NoteResponse>? Notes;
|
||||
public List<UserResponse>? Users;
|
||||
public List<BiteResponse>? Bites;
|
||||
}
|
||||
}
|
|
@ -751,7 +751,8 @@ public static class QueryableExtensions
|
|||
.Include(p => p.Note.Renote.Renote.User.UserProfile)
|
||||
.Include(p => p.Note.Reply.User.UserProfile)
|
||||
.Include(p => p.FollowRequest.Follower.UserProfile)
|
||||
.Include(p => p.FollowRequest.Followee.UserProfile);
|
||||
.Include(p => p.FollowRequest.Followee.UserProfile)
|
||||
.Include(p => p.Bite);
|
||||
}
|
||||
|
||||
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
||||
|
|
Loading…
Add table
Reference in a new issue