fix: prevent potential component state updates after disposal and implement dedicated repository for quiz results
This commit is contained in:
@@ -18,14 +18,15 @@ public class GetUserProfileQueryHandler : IRequestHandler<GetUserProfileQuery, R
|
||||
public async Task<Result<UserProfileDto>> Handle(GetUserProfileQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
|
||||
var profile = await dbContext.Users
|
||||
|
||||
var userRaw = await dbContext.Users
|
||||
.Where(u => u.Id == request.UserId)
|
||||
.Select(u => new UserProfileDto
|
||||
.Select(u => new
|
||||
{
|
||||
Email = u.Email ?? string.Empty,
|
||||
UserId = u.Id,
|
||||
AITokensUsed = u.AITokensUsed,
|
||||
TenantId = u.TenantId != null && u.TenantId.Length == 36 ? new Guid(u.TenantId) : Guid.Empty,
|
||||
TenantIdString = u.TenantId,
|
||||
Plan = u.SubscriptionPlan != null ? new SubscriptionPlanDto
|
||||
{
|
||||
Id = u.SubscriptionPlan.Id,
|
||||
@@ -33,12 +34,17 @@ public class GetUserProfileQueryHandler : IRequestHandler<GetUserProfileQuery, R
|
||||
AITokenLimit = u.SubscriptionPlan.AITokenLimit,
|
||||
MonthlyPrice = u.SubscriptionPlan.MonthlyPrice
|
||||
} : new SubscriptionPlanDto(),
|
||||
AverageQuizScore = u.QuizResults.Any(q => q.TotalQuestions > 0)
|
||||
? (int)u.QuizResults.Where(q => q.TotalQuestions > 0).Average(q => (double)q.Score / q.TotalQuestions * 100)
|
||||
: 0,
|
||||
QuizResults = u.QuizResults.Select(q => new
|
||||
{
|
||||
q.Score,
|
||||
q.TotalQuestions,
|
||||
q.Id,
|
||||
q.Topic,
|
||||
q.Percentage,
|
||||
q.CompletedDate
|
||||
}).ToList(),
|
||||
DisplayName = u.DisplayName,
|
||||
BooksReadCount = u.Ebooks.Count(),
|
||||
ConceptsMappedCount = dbContext.KnowledgeUnits.Count(k => k.TenantId == u.TenantId || k.TenantId == "global" || string.IsNullOrEmpty(k.TenantId)),
|
||||
LastReadBook = u.Ebooks.OrderByDescending(e => e.LastReadDate).Select(e => new LastReadBookDto
|
||||
{
|
||||
Id = e.Id,
|
||||
@@ -55,26 +61,6 @@ public class GetUserProfileQueryHandler : IRequestHandler<GetUserProfileQuery, R
|
||||
Description = e.Description,
|
||||
IsReadyForReading = e.IsReadyForReading
|
||||
}).FirstOrDefault(),
|
||||
RecentQuizzes = u.QuizResults.OrderByDescending(q => q.CompletedDate).Take(5).Select(q => new QuizResultDto
|
||||
{
|
||||
Id = q.Id,
|
||||
Topic = q.Topic,
|
||||
Score = q.Score,
|
||||
TotalQuestions = q.TotalQuestions,
|
||||
Percentage = q.Percentage,
|
||||
CompletedDate = q.CompletedDate
|
||||
}).ToList(),
|
||||
MappedConcepts = dbContext.KnowledgeUnits
|
||||
.Where(k => k.TenantId == u.TenantId || k.TenantId == "global" || string.IsNullOrEmpty(k.TenantId))
|
||||
.OrderByDescending(k => k.CreatedAt)
|
||||
.Take(6)
|
||||
.Select(k => new MappedConceptDto
|
||||
{
|
||||
Id = k.Id,
|
||||
Type = k.Type.ToString(),
|
||||
Content = k.Content
|
||||
})
|
||||
.ToList(),
|
||||
Roles = dbContext.UserRoles
|
||||
.Where(ur => ur.UserId == u.Id)
|
||||
.Join(dbContext.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name!)
|
||||
@@ -82,11 +68,59 @@ public class GetUserProfileQueryHandler : IRequestHandler<GetUserProfileQuery, R
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (profile == null)
|
||||
if (userRaw == null)
|
||||
{
|
||||
return Result.Fail("Profile not found.");
|
||||
}
|
||||
|
||||
var tenantId = userRaw.TenantIdString;
|
||||
var mappedConcepts = await dbContext.KnowledgeUnits
|
||||
.Where(k => k.TenantId == tenantId || k.TenantId == "global" || string.IsNullOrEmpty(k.TenantId))
|
||||
.OrderByDescending(k => k.CreatedAt)
|
||||
.Take(6)
|
||||
.Select(k => new MappedConceptDto
|
||||
{
|
||||
Id = k.Id,
|
||||
Type = k.Type.ToString(),
|
||||
Content = k.Content
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var conceptsMappedCount = await dbContext.KnowledgeUnits
|
||||
.CountAsync(k => k.TenantId == tenantId || k.TenantId == "global" || string.IsNullOrEmpty(k.TenantId), cancellationToken);
|
||||
|
||||
int averageQuizScore = 0;
|
||||
var validQuizzes = userRaw.QuizResults.Where(q => q.TotalQuestions > 0).ToList();
|
||||
if (validQuizzes.Count > 0)
|
||||
{
|
||||
averageQuizScore = (int)(validQuizzes.Average(q => (double)q.Score / q.TotalQuestions) * 100);
|
||||
}
|
||||
|
||||
var profile = new UserProfileDto
|
||||
{
|
||||
Email = userRaw.Email,
|
||||
UserId = userRaw.UserId,
|
||||
AITokensUsed = userRaw.AITokensUsed,
|
||||
TenantId = userRaw.TenantIdString != null && userRaw.TenantIdString.Length == 36 ? new Guid(userRaw.TenantIdString) : Guid.Empty,
|
||||
Plan = userRaw.Plan,
|
||||
AverageQuizScore = averageQuizScore,
|
||||
DisplayName = userRaw.DisplayName,
|
||||
BooksReadCount = userRaw.BooksReadCount,
|
||||
ConceptsMappedCount = conceptsMappedCount,
|
||||
LastReadBook = userRaw.LastReadBook,
|
||||
RecentQuizzes = userRaw.QuizResults.OrderByDescending(q => q.CompletedDate).Take(5).Select(q => new QuizResultDto
|
||||
{
|
||||
Id = q.Id,
|
||||
Topic = q.Topic,
|
||||
Score = q.Score,
|
||||
TotalQuestions = q.TotalQuestions,
|
||||
Percentage = q.Percentage,
|
||||
CompletedDate = q.CompletedDate
|
||||
}).ToList(),
|
||||
MappedConcepts = mappedConcepts,
|
||||
Roles = userRaw.Roles
|
||||
};
|
||||
|
||||
return Result.Ok(profile);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user