fix: avoid feedback screenshot concurrency save
This commit is contained in:
@@ -38,8 +38,7 @@ public class AttachMyFeedbackScreenshotHandler(
|
|||||||
Guid reporterUserId = User.GetUserId();
|
Guid reporterUserId = User.GetUserId();
|
||||||
|
|
||||||
FeedbackReport? report = await dbContext.FeedbackReports
|
FeedbackReport? report = await dbContext.FeedbackReports
|
||||||
.Include(candidate => candidate.Tags)
|
.AsNoTracking()
|
||||||
.Include(candidate => candidate.Screenshot)
|
|
||||||
.SingleOrDefaultAsync(
|
.SingleOrDefaultAsync(
|
||||||
candidate => candidate.Id == id && candidate.ReporterUserId == reporterUserId,
|
candidate => candidate.Id == id && candidate.ReporterUserId == reporterUserId,
|
||||||
ct);
|
ct);
|
||||||
@@ -50,7 +49,11 @@ public class AttachMyFeedbackScreenshotHandler(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report.Screenshot is not null)
|
bool hasScreenshot = await dbContext.FeedbackScreenshots
|
||||||
|
.AsNoTracking()
|
||||||
|
.AnyAsync(candidate => candidate.FeedbackReportId == report.Id, ct);
|
||||||
|
|
||||||
|
if (hasScreenshot)
|
||||||
{
|
{
|
||||||
AddError("A screenshot is already attached to this feedback report.");
|
AddError("A screenshot is already attached to this feedback report.");
|
||||||
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
|
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
|
||||||
@@ -94,7 +97,7 @@ public class AttachMyFeedbackScreenshotHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DateTimeOffset now = DateTimeOffset.UtcNow;
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||||
report.Screenshot = new FeedbackScreenshot
|
FeedbackScreenshot screenshot = new()
|
||||||
{
|
{
|
||||||
Id = screenshotId,
|
Id = screenshotId,
|
||||||
FeedbackReportId = report.Id,
|
FeedbackReportId = report.Id,
|
||||||
@@ -105,10 +108,45 @@ public class AttachMyFeedbackScreenshotHandler(
|
|||||||
BlobName = blobName,
|
BlobName = blobName,
|
||||||
CreatedAt = now,
|
CreatedAt = now,
|
||||||
};
|
};
|
||||||
report.LastActivityAt = now;
|
|
||||||
|
|
||||||
|
await using Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction transaction =
|
||||||
|
await dbContext.Database.BeginTransactionAsync(ct);
|
||||||
|
|
||||||
|
dbContext.FeedbackScreenshots.Add(screenshot);
|
||||||
|
try
|
||||||
|
{
|
||||||
await dbContext.SaveChangesAsync(ct);
|
await dbContext.SaveChangesAsync(ct);
|
||||||
await SendOkAsync(report.ToDto(), ct);
|
}
|
||||||
|
catch (DbUpdateException)
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync(ct);
|
||||||
|
AddError("A screenshot is already attached to this feedback report.");
|
||||||
|
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int updatedRows = await dbContext.FeedbackReports
|
||||||
|
.Where(candidate => candidate.Id == report.Id && candidate.ReporterUserId == reporterUserId)
|
||||||
|
.ExecuteUpdateAsync(
|
||||||
|
setters => setters.SetProperty(candidate => candidate.LastActivityAt, now),
|
||||||
|
ct);
|
||||||
|
|
||||||
|
if (updatedRows == 0)
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync(ct);
|
||||||
|
await SendNotFoundAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await transaction.CommitAsync(ct);
|
||||||
|
|
||||||
|
FeedbackReport responseReport = await dbContext.FeedbackReports
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(candidate => candidate.Tags)
|
||||||
|
.Include(candidate => candidate.Screenshot)
|
||||||
|
.SingleAsync(candidate => candidate.Id == report.Id, ct);
|
||||||
|
|
||||||
|
await SendOkAsync(responseReport.ToDto(), ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string NormalizeFileName(string? fileName, string extension)
|
private static string NormalizeFileName(string? fileName, string extension)
|
||||||
|
|||||||
Reference in New Issue
Block a user