feat(one-time-downloads): add expiry and retry configuration
Introduce new environment variables to control the behavior of one-time download boxes: - `WARPBOX_ONE_TIME_DOWNLOAD_EXPIRY_SECONDS`: Sets the lifetime of a one-time box after uploads are complete. - `WARPBOX_ONE_TIME_DOWNLOAD_RETRY_ON_FAILURE`: Determines whether a box remains available if the ZIP creation or transfer fails. To support these settings, the ZIP delivery process was refactored to use a temporary file. This ensures that a one-time box is only marked as consumed after the file has been successfully transferred to the client, preventing data loss on network interruptions. Additionally, added a `DecorateFiles` helper in the box store to reduce code duplication.
This commit is contained in:
@@ -47,7 +47,11 @@ func TestStartRetentionBeginsWhenEveryFileIsTerminal(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartRetentionSkipsOneTimeDownload(t *testing.T) {
|
||||
func TestStartRetentionUsesConfiguredOneTimeDownloadExpiry(t *testing.T) {
|
||||
restoreExpiry := OneTimeDownloadExpiry()
|
||||
defer SetOneTimeDownloadExpiry(restoreExpiry)
|
||||
SetOneTimeDownloadExpiry(30)
|
||||
|
||||
manifest := models.BoxManifest{
|
||||
RetentionSecs: 10,
|
||||
OneTimeDownload: true,
|
||||
@@ -56,11 +60,38 @@ func TestStartRetentionSkipsOneTimeDownload(t *testing.T) {
|
||||
{ID: "two", Status: models.FileStatusReady},
|
||||
},
|
||||
}
|
||||
before := time.Now().UTC()
|
||||
|
||||
startRetentionIfTerminalUnlocked(&manifest)
|
||||
|
||||
if manifest.ExpiresAt.IsZero() {
|
||||
t.Fatal("expected one-time download expiry to start from configured expiry")
|
||||
}
|
||||
if manifest.ExpiresAt.Before(before.Add(29 * time.Second)) {
|
||||
t.Fatalf("expected configured one-time expiry, got %s", manifest.ExpiresAt)
|
||||
}
|
||||
if manifest.ExpiresAt.After(before.Add(31 * time.Second)) {
|
||||
t.Fatalf("expected configured one-time expiry near 30s, got %s", manifest.ExpiresAt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartRetentionSkipsOneTimeDownloadWhenExpiryZero(t *testing.T) {
|
||||
restoreExpiry := OneTimeDownloadExpiry()
|
||||
defer SetOneTimeDownloadExpiry(restoreExpiry)
|
||||
SetOneTimeDownloadExpiry(0)
|
||||
|
||||
manifest := models.BoxManifest{
|
||||
RetentionSecs: 10,
|
||||
OneTimeDownload: true,
|
||||
Files: []models.BoxFile{
|
||||
{ID: "one", Status: models.FileStatusReady},
|
||||
},
|
||||
}
|
||||
|
||||
startRetentionIfTerminalUnlocked(&manifest)
|
||||
|
||||
if !manifest.ExpiresAt.IsZero() {
|
||||
t.Fatalf("expected one-time download box to avoid retention expiry, got %s", manifest.ExpiresAt)
|
||||
t.Fatalf("expected zero one-time expiry to keep expiry unset, got %s", manifest.ExpiresAt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +146,32 @@ func TestListFilesSkipsSymlinks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestThumbnailTasksSkipOneTimeDownloadBoxes(t *testing.T) {
|
||||
restoreUploadRoot := UploadRoot()
|
||||
defer SetUploadRoot(restoreUploadRoot)
|
||||
SetUploadRoot(t.TempDir())
|
||||
|
||||
boxID := "0123456789abcdef0123456789abcdef"
|
||||
if err := os.MkdirAll(BoxPath(boxID), 0755); err != nil {
|
||||
t.Fatalf("MkdirAll returned error: %v", err)
|
||||
}
|
||||
if err := WriteManifest(boxID, models.BoxManifest{
|
||||
OneTimeDownload: true,
|
||||
Files: []models.BoxFile{{
|
||||
ID: "0123456789abcdef",
|
||||
Name: "image.png",
|
||||
MimeType: "image/png",
|
||||
Status: models.FileStatusReady,
|
||||
}},
|
||||
}); err != nil {
|
||||
t.Fatalf("WriteManifest returned error: %v", err)
|
||||
}
|
||||
|
||||
if tasks := collectBoxThumbnailTasks(boxID, 10); len(tasks) != 0 {
|
||||
t.Fatalf("expected no thumbnail tasks for one-time box, got %#v", tasks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoxPasswordUsesBcryptAndVerifiesLegacy(t *testing.T) {
|
||||
restoreUploadRoot := UploadRoot()
|
||||
defer SetUploadRoot(restoreUploadRoot)
|
||||
|
||||
Reference in New Issue
Block a user