- JWT secret auto-generates and persists to <STORAGE_PATH>/.jwt_secret - Remove setup token: first admin setup is open until system initialized - Fix schema.sql: move CREATE EXTENSION pg_trgm/ltree to top - Update login UI and auth.js to remove setup token fields
5.1 KiB
Executable File
14 - Trash Feature
Soft-delete for files and folders. Items go to a per-user trash bin instead of being permanently removed. Configurable retention period with automatic cleanup.
Architecture
Follows the hexagonal architecture:
-
Domain Layer (
/src/domain/):- Entities: TrashedItem representing files and folders in the trash
- Repository interfaces: TrashRepository defining trash management operations
-
Application Layer (
/src/application/):- DTOs: TrashedItemDto for data transfer between layers
- Ports: TrashUseCase defining available operations
- Services: TrashService implementing the trash use cases
-
Infrastructure Layer (
/src/infrastructure/):- Repositories: TrashDbRepository (PostgreSQL) — reads from
storage.trash_itemsVIEW, manages soft-delete flags - Trash-related methods in file/folder repositories:
FileBlobWriteRepository::move_to_trash(),FolderDbRepository::move_to_trash(), etc. - Services: TrashCleanupService for automatic cleanup of expired items
- Repositories: TrashDbRepository (PostgreSQL) — reads from
-
Interface Layer (
/src/interfaces/):- API handlers:
trash_handler.rswith HTTP endpoints for trash operations - Routes: updated
routes.rsto include trash endpoints
- API handlers:
Storage Model
Trash uses a soft-delete model in PostgreSQL:
- Files and folders have
is_trashed(BOOLEAN) andtrashed_at(TIMESTAMPTZ) columns - When an item is trashed,
is_trashedis set toTRUEandtrashed_atrecords the timestamp original_parent_id/original_folder_idstores the original location for restore- The
storage.trash_itemsVIEW provides a unified list of all trashed items (files + folders) - No physical file movement occurs — blob content stays at
.blobs/{prefix}/{hash}.blob - Permanent deletion removes the DB row and decrements the blob reference counter
CREATE OR REPLACE VIEW storage.trash_items AS
SELECT id, name, 'file' AS item_type, folder_id AS parent_id,
user_id, size, mime_type, trashed_at, created_at
FROM storage.files WHERE is_trashed = TRUE
UNION ALL
SELECT id, name, 'folder' AS item_type, parent_id,
user_id, 0 AS size, NULL AS mime_type, trashed_at, created_at
FROM storage.folders WHERE is_trashed = TRUE;
Key Features
- Soft Deletion — files and folders are flagged as trashed, not immediately deleted
- Per-User Trash — each user has an isolated trash bin (filtered by
user_id) - Retention Policy — items auto-delete after a configurable period
- Restoration — items can be restored to their original location via
original_parent_id/original_folder_id - Permanent Deletion — items can be permanently deleted before retention expires (removes DB row + decrements blob ref)
- Empty Trash — wipe everything in the trash at once
API Endpoints
GET /api/trashorGET /api/trash/— list all items in the user's trashDELETE /api/trash/files/:id— move a file to trashDELETE /api/trash/folders/:id— move a folder to trashPOST /api/trash/:id/restore— restore an item to its original locationDELETE /api/trash/:id— permanently delete an item from trashDELETE /api/trash/empty— empty the entire trash bin
Implementation Details
TrashDbRepository
File: src/infrastructure/repositories/pg/trash_db_repository.rs
pub struct TrashDbRepository {
pool: Arc<PgPool>,
retention_days: u32,
}
Key methods:
get_trash_items(user_id)— SELECT fromstorage.trash_itemsWHEREuser_id = $1clear_trash(user_id)— DELETE fromstorage.filesandstorage.foldersWHEREis_trashed = TRUE AND user_id = $1get_expired_items()— finds items wheretrashed_at + retention_days < NOW()
TrashService
File: src/application/services/trash_service.rs
Constructor: TrashService::new(trash_repo, file_read, file_write, folder_repo, retention_days)
Orchestrates trash operations by delegating to the appropriate repository:
- Moving a file to trash →
FileBlobWriteRepository::move_to_trash() - Moving a folder to trash →
FolderDbRepository::move_to_trash() - Permanent deletion → removes DB row + calls
DedupService::decrement_ref()to clean blob if unreferenced
TrashCleanupService
File: src/infrastructure/services/trash_cleanup_service.rs
Background job that runs every 24 hours to permanently delete items past the retention period.
Testing
-
Unit Tests — testing TrashService:
- Move files and folders to trash
- Restore items from trash
- Permanent deletion
- Empty trash operation
-
Integration Tests — Python script hitting the API endpoints:
- End-to-end testing of all trash operations
- Verification of move, list, restore, and delete behavior
Configuration
- OXICLOUD_ENABLE_TRASH: enable/disable the trash feature via FeaturesConfig (default: true)
- OXICLOUD_TRASH_RETENTION_DAYS: days to keep items before automatic deletion (default: 30, via StorageConfig)