mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-09-21 05:21:43 +00:00
feat: retain uploaded STL files for recovery
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "manual_upload_files" ADD COLUMN "retainedAt" TIMESTAMP(3);
|
||||||
@@ -937,6 +937,7 @@ model ManualUploadFile {
|
|||||||
filePath String // Path on shared volume
|
filePath String // Path on shared volume
|
||||||
fileSize BigInt
|
fileSize BigInt
|
||||||
packageId String? // Set after processing
|
packageId String? // Set after processing
|
||||||
|
retainedAt DateTime?
|
||||||
|
|
||||||
upload ManualUpload @relation(fields: [uploadId], references: [id], onDelete: Cascade)
|
upload ManualUpload @relation(fields: [uploadId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
|||||||
@@ -180,12 +180,25 @@ verify_file_references() {
|
|||||||
local database_user="${POSTGRES_USER:-dragons}"
|
local database_user="${POSTGRES_USER:-dragons}"
|
||||||
local database_name="${POSTGRES_DB:-dragonsstash}"
|
local database_name="${POSTGRES_DB:-dragonsstash}"
|
||||||
docker compose exec -T db psql --no-psqlrc --tuples-only --no-align --quiet \
|
docker compose exec -T db psql --no-psqlrc --tuples-only --no-align --quiet \
|
||||||
|
--field-separator=$'\t' \
|
||||||
--username "$database_user" --dbname "$database_name" \
|
--username "$database_user" --dbname "$database_name" \
|
||||||
--command 'SELECT "filePath" FROM "manual_upload_files" ORDER BY "filePath"' |
|
--command "SELECT 'legacy', \"filePath\" FROM \"manual_upload_files\" WHERE \"retainedAt\" IS NULL
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'retained', \"filePath\" FROM \"manual_upload_files\" WHERE \"retainedAt\" IS NOT NULL
|
||||||
|
ORDER BY 2" |
|
||||||
docker compose --profile backup run --rm --no-deps -T --entrypoint bash \
|
docker compose --profile backup run --rm --no-deps -T --entrypoint bash \
|
||||||
-v "$uploads_volume:/data/uploads:ro" backup -ceu '
|
-v "$uploads_volume:/data/uploads:ro" backup -ceu '
|
||||||
missing=0
|
missing=0
|
||||||
while IFS= read -r file_path; do
|
while IFS="$(printf "\t")" read -r retention file_path; do
|
||||||
|
if [[ "$retention" == "legacy" ]]; then
|
||||||
|
printf "Warning: legacy manual-upload file reference is not required because retainedAt is NULL: %s\\n" "$file_path" >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ "$retention" != "retained" ]]; then
|
||||||
|
printf "Unexpected retention status for database reference: %s\\n" "$file_path" >&2
|
||||||
|
missing=1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
case "$file_path" in
|
case "$file_path" in
|
||||||
/data/uploads/*) relative_path="${file_path#/data/uploads/}" ;;
|
/data/uploads/*) relative_path="${file_path#/data/uploads/}" ;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export async function POST(request: Request) {
|
|||||||
fileName: file.name,
|
fileName: file.name,
|
||||||
filePath,
|
filePath,
|
||||||
fileSize: BigInt(file.size),
|
fileSize: BigInt(file.size),
|
||||||
|
retainedAt: new Date(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import path from "path";
|
|
||||||
import { rm } from "fs/promises";
|
import { rm } from "fs/promises";
|
||||||
import { db } from "./db/client.js";
|
import { db } from "./db/client.js";
|
||||||
import { childLogger } from "./util/logger.js";
|
import { childLogger } from "./util/logger.js";
|
||||||
@@ -200,12 +199,4 @@ export async function processManualUpload(uploadId: string): Promise<void> {
|
|||||||
data: { status: "FAILED", errorMessage: message },
|
data: { status: "FAILED", errorMessage: message },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up uploaded files
|
|
||||||
try {
|
|
||||||
const uploadDir = path.join("/data/uploads", uploadId);
|
|
||||||
await rm(uploadDir, { recursive: true, force: true });
|
|
||||||
} catch {
|
|
||||||
// Best-effort cleanup
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user