fix: Optional OCR-Assisted Draft Pre-Fill
This commit is contained in:
@@ -129,31 +129,42 @@ public class DigitizationBatchesController : ControllerBase
|
||||
var batch = await _batches.GetByIdAsync(id);
|
||||
var presignedUrl = await _storage.GetPresignedUrlAsync(batch.DocumentRef);
|
||||
|
||||
var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
|
||||
var cutoff = DateTimeOffset.UtcNow.AddMinutes(-5);
|
||||
var recentAccess = await _db.DigitizationEvents.AnyAsync(e =>
|
||||
e.BatchId == id &&
|
||||
e.EventType == DigitizationEventType.DocumentAccessed &&
|
||||
e.ActorUserId == userId &&
|
||||
e.OccurredAt >= cutoff);
|
||||
|
||||
if (!recentAccess)
|
||||
{
|
||||
_db.DigitizationEvents.Add(new DigitizationEvent
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
BatchId = id,
|
||||
EventType = DigitizationEventType.DocumentAccessed,
|
||||
ActorUserId = userId,
|
||||
OccurredAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
await RecordDocumentAccessAsync(id);
|
||||
|
||||
return Ok(ApiResponse<BatchDetailResponse>.Ok(
|
||||
BatchDetailResponse.FromEntity(batch, presignedUrl)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Streams the scanned document for in-app viewing (same auth and audit as GET batch).
|
||||
/// Proxied through the API so the workstation can render PDFs without cross-origin iframe issues.
|
||||
/// </summary>
|
||||
[HttpGet("{id:guid}/document")]
|
||||
[Produces("application/pdf", "image/jpeg", "image/png", "application/octet-stream")]
|
||||
[ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetDocument(Guid id)
|
||||
{
|
||||
var batch = await _batches.GetByIdAsync(id);
|
||||
|
||||
if (batch.DocumentRef == "live-capture")
|
||||
return NotFound(ApiResponse<object>.Fail(
|
||||
404, "This batch has no scanned document.", "NO_DOCUMENT"));
|
||||
|
||||
var scanned = await _db.ScannedDocuments
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(d => d.BatchId == id);
|
||||
|
||||
var contentType = scanned?.ContentType ?? "application/octet-stream";
|
||||
|
||||
await RecordDocumentAccessAsync(id);
|
||||
|
||||
var stream = await _storage.DownloadAsync(batch.DocumentRef);
|
||||
Response.Headers.CacheControl = "private, max-age=300";
|
||||
return File(stream, contentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists batches with optional filters and pagination.
|
||||
/// </summary>
|
||||
@@ -265,4 +276,27 @@ public class DigitizationBatchesController : ControllerBase
|
||||
var result = await _batchEventService.GetEventsAsync(id, afterCursor, pageSize);
|
||||
return Ok(ApiResponse<CursorPagedResult<BatchEventResponse>>.Ok(result));
|
||||
}
|
||||
|
||||
private async Task RecordDocumentAccessAsync(Guid batchId)
|
||||
{
|
||||
var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
|
||||
var cutoff = DateTimeOffset.UtcNow.AddMinutes(-5);
|
||||
var recentAccess = await _db.DigitizationEvents.AnyAsync(e =>
|
||||
e.BatchId == batchId &&
|
||||
e.EventType == DigitizationEventType.DocumentAccessed &&
|
||||
e.ActorUserId == userId &&
|
||||
e.OccurredAt >= cutoff);
|
||||
|
||||
if (recentAccess) return;
|
||||
|
||||
_db.DigitizationEvents.Add(new DigitizationEvent
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
BatchId = batchId,
|
||||
EventType = DigitizationEventType.DocumentAccessed,
|
||||
ActorUserId = userId,
|
||||
OccurredAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,8 @@ public class BatchService : IBatchService
|
||||
patientId ??= supersededBatch.PatientId;
|
||||
}
|
||||
|
||||
var (objectKey, sha256, fileSize) = await _storage.UploadAsync(fileStream, contentType, Guid.NewGuid());
|
||||
var batchId = Guid.NewGuid();
|
||||
var (objectKey, sha256, fileSize) = await _storage.UploadAsync(fileStream, contentType, batchId);
|
||||
|
||||
// Duplicate detection: same SHA-256 for same patient within 24 hours
|
||||
if (patientId.HasValue)
|
||||
@@ -101,7 +102,6 @@ public class BatchService : IBatchService
|
||||
}
|
||||
}
|
||||
|
||||
var batchId = Guid.NewGuid();
|
||||
var batch = new DigitizationBatch
|
||||
{
|
||||
Id = batchId,
|
||||
|
||||
Reference in New Issue
Block a user