mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-05 05:31:31 +02:00
Library files now move to a configurable-retention trash bin on delete
instead of being hard-deleted from disk (default 30 days). Admins get a
"Purge old" bulk action on the File Manager with a live preview, plus an
optional auto-purge setting in Settings → File Manager that runs the same
operation once per 24h when enabled (default off). Regular users see and
manage their own trashed files; admins see everyone's. External (linked)
files bypass trash since their bytes aren't under Bambuddy's control.
- New `library:purge` permission (admin-only by default)
- Nullable indexed `deleted_at` column on library_files; dialect-aware
ALTER TABLE so the column actually gets added on PostgreSQL (raw
DATETIME is SQLite-only syntax)
- New `LibraryFile.active()` classmethod; every query site routed through
it so trashed rows don't leak into listings, print dispatch, MakerWorld
dedupe, or stats
- Trash page: select-all + bulk restore/delete, per-row checkboxes, wider
layout so datetime columns don't clip
- Auto-purge: 24h throttle via `library_auto_purge_last_run` setting so
the 15-minute sweeper cadence still runs the purge at most once per day
- Save toast wired into every trash/auto-purge setting change
- 17 new backend integration tests (service + routes + auto-purge throttle),
8 new frontend tests, localised across all 8 UI languages
- Wiki + website feature entries updated
60 lines
1.3 KiB
Python
60 lines
1.3 KiB
Python
"""Schemas for the library trash bin + bulk purge (#1008)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class PurgePreviewRequest(BaseModel):
|
|
older_than_days: int = Field(ge=1, le=3650, description="Age threshold in days.")
|
|
include_never_printed: bool = True
|
|
|
|
|
|
class PurgePreviewResponse(BaseModel):
|
|
count: int
|
|
total_bytes: int
|
|
sample_filenames: list[str]
|
|
older_than_days: int
|
|
include_never_printed: bool
|
|
|
|
|
|
class PurgeRequest(BaseModel):
|
|
older_than_days: int = Field(ge=1, le=3650)
|
|
include_never_printed: bool = True
|
|
|
|
|
|
class PurgeResponse(BaseModel):
|
|
moved_to_trash: int
|
|
|
|
|
|
class TrashFile(BaseModel):
|
|
id: int
|
|
filename: str
|
|
file_size: int
|
|
thumbnail_path: str | None = None
|
|
folder_id: int | None = None
|
|
folder_name: str | None = None
|
|
created_by_id: int | None = None
|
|
created_by_username: str | None = None
|
|
deleted_at: datetime
|
|
auto_purge_at: datetime
|
|
|
|
|
|
class TrashListResponse(BaseModel):
|
|
items: list[TrashFile]
|
|
total: int
|
|
retention_days: int
|
|
|
|
|
|
class TrashSettings(BaseModel):
|
|
retention_days: int = Field(ge=1, le=365)
|
|
auto_purge_enabled: bool = False
|
|
auto_purge_days: int = Field(default=90, ge=7, le=3650)
|
|
auto_purge_include_never_printed: bool = True
|
|
|
|
|
|
class EmptyTrashResponse(BaseModel):
|
|
deleted: int
|