@@ -17,6 +17,10 @@ import (
|
||||
// nothing about whether someone else's upload exists (ADR-033).
|
||||
var ErrUploadNotFound = errors.New("store: uploaded transcript not found")
|
||||
|
||||
// ErrUploadInProgress is returned by DeleteUpload for an upload that is still queued or
|
||||
// transcribing: the worker would write its result to a row that no longer exists.
|
||||
var ErrUploadInProgress = errors.New("store: uploaded transcript is still being processed")
|
||||
|
||||
// Uploaded transcripts are PRIVATE per-user content, stored in their own
|
||||
// RLS-scoped table (migration 017) — never in the shared `transcripts` (ADR-021).
|
||||
// Every method goes through withUser, so row-level security confines it to the
|
||||
@@ -103,6 +107,33 @@ func (s *Store) FailUpload(ctx context.Context, userID, id string, kind domain.U
|
||||
string(kind))
|
||||
}
|
||||
|
||||
// DeleteUpload removes one of the caller's finished (done or failed) uploads. An upload
|
||||
// still queued or transcribing is refused with ErrUploadInProgress and left untouched; one
|
||||
// that is not the caller's is ErrUploadNotFound, as for every other write (#37).
|
||||
func (s *Store) DeleteUpload(ctx context.Context, userID, id string) error {
|
||||
return s.withUser(ctx, userID, func(tx pgx.Tx) error {
|
||||
ct, err := tx.Exec(ctx,
|
||||
`DELETE FROM uploaded_transcripts
|
||||
WHERE id = $1 AND user_id = $2 AND status IN ('done', 'failed')`, id, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: delete upload: %w", err)
|
||||
}
|
||||
if ct.RowsAffected() > 0 {
|
||||
return nil
|
||||
}
|
||||
var exists bool
|
||||
if err := tx.QueryRow(ctx,
|
||||
`SELECT EXISTS (SELECT 1 FROM uploaded_transcripts WHERE id = $1 AND user_id = $2)`,
|
||||
id, userID).Scan(&exists); err != nil {
|
||||
return fmt.Errorf("store: delete upload: %w", err)
|
||||
}
|
||||
if exists {
|
||||
return ErrUploadInProgress
|
||||
}
|
||||
return ErrUploadNotFound
|
||||
})
|
||||
}
|
||||
|
||||
// updateUpload runs one UPDATE keyed on ($1 = id, $2 = userID) plus extra args,
|
||||
// and maps "no row touched" to ErrUploadNotFound — which is what a write to another
|
||||
// user's upload looks like under RLS (the row is invisible, not forbidden).
|
||||
|
||||
Reference in New Issue
Block a user