[backend/masto-client] Fix concurrent DbContext use in UserRenderer
This commit is contained in:
parent
685cb7d0b9
commit
b9724e29fb
1 changed files with 57 additions and 20 deletions
|
@ -18,15 +18,18 @@ public class UserRenderer(
|
||||||
{
|
{
|
||||||
private readonly string _transparent = $"https://{config.Value.WebDomain}/assets/transparent.png";
|
private readonly string _transparent = $"https://{config.Value.WebDomain}/assets/transparent.png";
|
||||||
|
|
||||||
public async Task<AccountEntity> RenderAsync(
|
public Task<AccountEntity> RenderAsync(User user, UserProfile? profile, User? localUser, bool source = false)
|
||||||
User user, UserProfile? profile, User? localUser, IEnumerable<EmojiEntity>? emoji = null, bool source = false
|
=> RenderAsync(user, profile, localUser, null, source);
|
||||||
|
|
||||||
|
private async Task<AccountEntity> RenderAsync(
|
||||||
|
User user, UserProfile? profile, User? localUser, UserRendererDto? data = null, bool source = false
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var acct = user.Username;
|
var acct = user.Username;
|
||||||
if (user.IsRemoteUser)
|
if (user.IsRemoteUser)
|
||||||
acct += $"@{user.Host}";
|
acct += $"@{user.Host}";
|
||||||
|
|
||||||
var profileEmoji = emoji?.Where(p => user.Emojis.Contains(p.Id)).ToList() ?? await GetEmojiAsync([user]);
|
var profileEmoji = data?.Emoji.Where(p => user.Emojis.Contains(p.Id)).ToList() ?? await GetEmojiAsync([user]);
|
||||||
var mentions = profile?.Mentions ?? [];
|
var mentions = profile?.Mentions ?? [];
|
||||||
var fields = profile != null
|
var fields = profile != null
|
||||||
? await profile.Fields
|
? await profile.Fields
|
||||||
|
@ -45,14 +48,8 @@ public class UserRenderer(
|
||||||
? profile?.Fields.Select(p => new Field { Name = p.Name, Value = p.Value }).ToList() ?? []
|
? profile?.Fields.Select(p => new Field { Name = p.Name, Value = p.Value }).ToList() ?? []
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
user.Avatar ??= await db.Users.Where(p => p.Id == user.Id)
|
var avatarAlt = data?.AvatarAlt.GetValueOrDefault(user.Id);
|
||||||
.Include(p => p.Avatar)
|
var bannerAlt = data?.BannerAlt.GetValueOrDefault(user.Id);
|
||||||
.Select(p => p.Avatar)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
user.Banner ??= await db.Users.Where(p => p.Id == user.Id)
|
|
||||||
.Include(p => p.Banner)
|
|
||||||
.Select(p => p.Banner)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
var res = new AccountEntity
|
var res = new AccountEntity
|
||||||
{
|
{
|
||||||
|
@ -71,10 +68,10 @@ public class UserRenderer(
|
||||||
Url = profile?.Url ?? user.Uri ?? user.GetPublicUrl(config.Value),
|
Url = profile?.Url ?? user.Uri ?? user.GetPublicUrl(config.Value),
|
||||||
Uri = user.Uri ?? user.GetPublicUri(config.Value),
|
Uri = user.Uri ?? user.GetPublicUri(config.Value),
|
||||||
AvatarStaticUrl = user.GetAvatarUrl(config.Value), //TODO
|
AvatarStaticUrl = user.GetAvatarUrl(config.Value), //TODO
|
||||||
AvatarDescription = user.Avatar?.Comment ?? "",
|
AvatarDescription = avatarAlt ?? "",
|
||||||
HeaderUrl = user.GetBannerUrl(config.Value) ?? _transparent,
|
HeaderUrl = user.GetBannerUrl(config.Value) ?? _transparent,
|
||||||
HeaderStaticUrl = user.GetBannerUrl(config.Value) ?? _transparent, //TODO
|
HeaderStaticUrl = user.GetBannerUrl(config.Value) ?? _transparent, //TODO
|
||||||
HeaderDescription = user.Banner?.Comment ?? "",
|
HeaderDescription = bannerAlt ?? "",
|
||||||
MovedToAccount = null, //TODO
|
MovedToAccount = null, //TODO
|
||||||
IsBot = user.IsBot,
|
IsBot = user.IsBot,
|
||||||
IsDiscoverable = user.IsExplorable,
|
IsDiscoverable = user.IsExplorable,
|
||||||
|
@ -98,8 +95,9 @@ public class UserRenderer(
|
||||||
Fields = fieldsSource,
|
Fields = fieldsSource,
|
||||||
Language = "",
|
Language = "",
|
||||||
Note = profile?.Description ?? "",
|
Note = profile?.Description ?? "",
|
||||||
Privacy = StatusEntity.EncodeVisibility(user.UserSettings?.DefaultNoteVisibility ??
|
Privacy =
|
||||||
Note.NoteVisibility.Public),
|
StatusEntity.EncodeVisibility(user.UserSettings?.DefaultNoteVisibility
|
||||||
|
?? Note.NoteVisibility.Public),
|
||||||
Sensitive = false,
|
Sensitive = false,
|
||||||
FollowRequestCount = await db.FollowRequests.CountAsync(p => p.Followee == user)
|
FollowRequestCount = await db.FollowRequests.CountAsync(p => p.Followee == user)
|
||||||
};
|
};
|
||||||
|
@ -127,16 +125,55 @@ public class UserRenderer(
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Dictionary<string, string?>> GetAvatarAltAsync(IEnumerable<User> users)
|
||||||
|
{
|
||||||
|
var ids = users.Select(p => p.Id).ToList();
|
||||||
|
return await db.Users
|
||||||
|
.Where(p => ids.Contains(p.Id))
|
||||||
|
.Include(p => p.Avatar)
|
||||||
|
.ToDictionaryAsync(p => p.Id, p => p.Avatar?.Comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Dictionary<string, string?>> GetBannerAltAsync(IEnumerable<User> users)
|
||||||
|
{
|
||||||
|
var ids = users.Select(p => p.Id).ToList();
|
||||||
|
return await db.Users
|
||||||
|
.Where(p => ids.Contains(p.Id))
|
||||||
|
.Include(p => p.Banner)
|
||||||
|
.ToDictionaryAsync(p => p.Id, p => p.Banner?.Comment);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<AccountEntity> RenderAsync(User user, User? localUser, List<EmojiEntity>? emoji = null)
|
public async Task<AccountEntity> RenderAsync(User user, User? localUser, List<EmojiEntity>? emoji = null)
|
||||||
{
|
{
|
||||||
return await RenderAsync(user, user.UserProfile, localUser, emoji);
|
var data = new UserRendererDto
|
||||||
|
{
|
||||||
|
Emoji = emoji ?? await GetEmojiAsync([user]),
|
||||||
|
AvatarAlt = await GetAvatarAltAsync([user]),
|
||||||
|
BannerAlt = await GetBannerAltAsync([user])
|
||||||
|
};
|
||||||
|
|
||||||
|
return await RenderAsync(user, user.UserProfile, localUser, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<AccountEntity>> RenderManyAsync(IEnumerable<User> users, User? localUser)
|
public async Task<IEnumerable<AccountEntity>> RenderManyAsync(IEnumerable<User> users, User? localUser)
|
||||||
{
|
{
|
||||||
var userList = users.ToList();
|
var userList = users.ToList();
|
||||||
if (userList.Count == 0) return [];
|
if (userList.Count == 0) return [];
|
||||||
var emoji = await GetEmojiAsync(userList);
|
|
||||||
return await userList.Select(p => RenderAsync(p, localUser, emoji)).AwaitAllAsync();
|
var data = new UserRendererDto
|
||||||
|
{
|
||||||
|
Emoji = await GetEmojiAsync(userList),
|
||||||
|
AvatarAlt = await GetAvatarAltAsync(userList),
|
||||||
|
BannerAlt = await GetBannerAltAsync(userList)
|
||||||
|
};
|
||||||
|
|
||||||
|
return await userList.Select(p => RenderAsync(p, p.UserProfile, localUser, data)).AwaitAllAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UserRendererDto
|
||||||
|
{
|
||||||
|
public required List<EmojiEntity> Emoji;
|
||||||
|
public required Dictionary<string, string?> AvatarAlt;
|
||||||
|
public required Dictionary<string, string?> BannerAlt;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue