Commit Graph

20 Commits

Author SHA1 Message Date
DioCrafts f678ff414e fix 2026-06-10 22:03:49 +02:00
Edouard Vanbelle bde7c83932 feat(content_hash): propagate etag and hash_content to */resources 2026-06-06 20:11:13 +02:00
Edouard Vanbelle 7db547a669 fix(name duplicate): fixed via NFC normalisation
TL;DR:

    fix duplicate filename via:

    ```
    docker exec <container> migrate-nfc-filenames --dry-run    # preview
    docker exec <container> migrate-nfc-filenames              # execute
    ```

 == issue ==

  Last week I uploaded Capture d'écran 2026-06-03 à 20.04.24.png from the web. It synced down to Nextcloud on my Mac. Two minutes later, the Web UI was showing the file twice.

  Both rows had:
  - the same name
  - the same size
  - the same content hash

  So why two rows? Because to PostgreSQL, the names weren't the same.

  Web upload (browser → Postgres):
    "é" stored as 1 codepoint  (U+00E9)        bytes: c3 a9     ← NFC

  NiextCloud client (macOS → Postgres):
    "é" stored as 2 codepoints (e + U+0301)    bytes: 65 cc 81  ← NFD

  macOS's APFS keeps filenames in NFD (decomposed); browsers send NFC (composed). Visually é and é are identical. To WHERE name = $1 they're two different keys. Our UNIQUE index on (folder_id, name, user_id) never fired — and the row count quietly drifted every time a Mac user touched an accented
  filename.

 == The fix is two halves ==

  1. No new duplicates — every name-receiving boundary (file upload, NC PUT, rename, MOVE, path lookup) now NFC-normalizes before touching the database. The storage invariant becomes "every stored name is NFC".
  2. Clean up existing data — one-shot migrate-nfc-filenames binary walks storage.files, NFC-normalizes any non-NFC row, and resolves the collisions we've accumulated. Same-content duplicates go to trash (recoverable); different-content collisions get renamed with a .duplicate suffix.

 == use of the clean up ==

    example of use (do not forget to define env **DATABASE_URL**)

    either
        `cargo run --bin migrate-nfc-filenames -- --dry-run`
    or
        `cargo build --bin migrate-nfc-filenames`
        `./target/debug/migrate-nfc-filenames --dry-run`

    example:
```
    % ./target/debug/migrate-nfc-filenames --dry-run
    === NFC filename migration (DRY RUN — no writes) ===

    Loaded 543 non-trashed file rows

    NORMALIZE  163451b5-5e6c-404b-9b1e-f4b01a2b7269  user=42433185-4717-416d-9a15-4580fff171ec  'Capture d’écran 2026-03-20 à 14.44.50.png' → 'Capture d’écran 2026-03-20 à 14.44.50.png'
    NORMALIZE  827dddec-4dd5-48c2-a120-dec5289f7d29  user=969deca6-7935-4f12-a430-4d636b62fa3e  'Capture d’écran 2026-04-03 à 15.43.38.png' → 'Capture d’écran 2026-04-03 à 15.43.38.png'
    NORMALIZE  09559934-a620-472d-9ba8-fc3cfeb6dc6f  user=a0643a21-0092-4a84-9dde-7ac4e76bc1a5  'Capture d’écran 2026-06-03 à 20.05.38.png' → 'Capture d’écran 2026-06-03 à 20.05.38.png'
    NORMALIZE  5ce6dbf9-0562-4758-8783-671aa9069590  user=a0643a21-0092-4a84-9dde-7ac4e76bc1a5  'Capture d’écran 2026-06-05 à 11.07.25.png' → 'Capture d’écran 2026-06-05 à 11.07.25.png'
    DEDUP      newer=26bcf82b-99cc-45c8-9d69-dd7e5c4484ff (trash, same blob)  older=df3adc67-a778-424d-a817-b930c75f3b06  user=a0643a21-0092-4a84-9dde-7ac4e76bc1a5  hash=0d2cc7b0ffce2850

    === Summary ===
      scanned                            : 543
      already in NFC                     : 538
      normalized in place (no collision) : 4
      dedup-trashed (same content)       : 1
      renamed to .duplicate              : 0

    DRY RUN — no rows were written. Re-run without --dry-run to apply.
```

    once valid remove --dry-run
2026-06-06 20:11:08 +02:00
Edouard Vanbelle 1b9d9af5c0 feat(etag): cascade tag change on each folerd's parent
on a file or folder change, the etag of each parent will be updated, this is O(n)
    this is required to ensure NextCloud client will be aware of changes

    In the future a Cursor will be better, this will be for OxiCloud-desktop
2026-06-06 18:49:14 +02:00
Edouard Vanbelle 0135930da9 refactor(file|folder): separate etag and blob_hash 2026-06-06 18:49:14 +02:00
Edouard Vanbelle 6696ba3ae4 fix(storage names): enure folder and file names are not using reserved chars
- create common function `validate_storage_name()` to check files & folder name
 - replace previous duplicate check with this one
 - better check on create_folder rename_folder (was only checking non empty)
 - use correct error class to ensure 400 on API (was 500)

fix: #345
note: no unit test here, but plan e2e test for that
next: improve UI to display error
2026-05-08 00:26:44 +02:00
Edouard Vanbelle badf35f08f chore: remove all executable attributes on non bash files 2026-04-01 23:14:42 +02:00
zjean 18518bedaf fix: resolve clippy warnings and rustfmt issues for CI compliance
Fix all clippy lints (collapsible if, clone on Copy, needless borrow,
redundant bindings, unused params) and apply rustfmt across the codebase.
Update test mocks to match Uuid-based trait signatures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:34:07 +01:00
Diocrafts 6b02c10942 perf: complete storage-layer UUID migration — eliminate UUID↔String round-trips
- Domain: Folder.owner_id + File.owner_id → Option<Uuid> (was Option<String>)
- Traits: folder_repository signatures accept Uuid directly (was &str)
- Infra: remove all fi.user_id::text / fo.user_id::text SQL casts in repos
- Infra: remove $N::uuid bind casts (columns are native UUID now)
- Services: eliminate to_string() bridge variables in folder_service,
  search_service, trash_service
- DTOs: boundary conversion to String only at API edge (file_dto, folder_dto)
- Ports: default impls compare Option<Uuid> directly
- Stubs: updated signatures to match trait

13 files changed across domain/application/infrastructure layers.
Compiles clean (cargo check passes).
2026-03-07 18:05:52 +01:00
Dionisio f2d35ca792 feat: auto-persist JWT secret, remove setup token requirement
- 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
2026-03-05 22:12:53 +01:00
Jan Wiebe 807370e194 style: apply cargo fmt formatting to existing codebase
Run `cargo fmt` across all Rust source files to enforce consistent
formatting (import ordering, line wrapping, match arm braces).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:33:18 +01:00
Dionisio 7737ed90c7 feat: folder ownership scoping, batch operations integration, frontend audit fixes
Backend:
- Add owner_id to Folder entity + FolderDto (DB user_id column)
- Add list_folders_by_owner to FolderRepository trait + PG impl
- Add list_folders_for_owner to FolderUseCase + FolderService
- Rewrite FolderHandler: all endpoints now scope by AuthUser
- Remove dead handler methods (list_folders_inner, list_folders_for_user, is_user_home_folder, folder_belongs_to_user)
- Add ownership check in get_folder (returns 404 on mismatch)

Batch operations:
- Add trash_service + zip_service to BatchOperationService
- New methods: trash_files, trash_folders, move_folders, download_zip
- New handlers: trash_batch, move_folders_batch, download_batch
- New routes: POST /api/batch/trash, /api/batch/folders/move, /api/batch/download

Frontend:
- Replace findUserHomeFolder (~130 lines) with resolveHomeFolder (~35 lines)
- Remove client-side folder filtering in loadFiles (backend now scopes)
- Rewrite batchDelete: N requests -> 1 POST /api/batch/trash
- Rewrite batchMove: N requests -> 2 POST max (files + folders)
- Rewrite batchDownload: N requests -> 1 POST /api/batch/download (ZIP)
- Search moved to backend, share system uses backend API
- Dark mode fixes, frontend audit improvements
2026-02-15 23:45:11 +01:00
Dionisio 4c98c5a657 style: apply cargo fmt to entire codebase
Standardize code formatting across all 173 Rust source files
using rustfmt. No functional changes - purely cosmetic.

This establishes a consistent code style baseline for the
project going forward.
2026-02-14 01:29:34 +01:00
Dionisio d31a413e57 chore: translate all Spanish comments and log messages to English 2026-02-12 09:41:25 +01:00
Dionisio c952e82b27 refactoring hexagonal architecture 2026-02-06 20:57:00 +01:00
Dionisio 52840e57df refactor: remove serde from domain entities for Clean Architecture compliance
- Remove Serialize/Deserialize from File, Folder, Session, User, Contact entities
- Create contact_persistence_dto.rs for JSONB persistence in infrastructure layer
- Update contact_pg_repository to use persistence DTOs
- Fix dependency on zip crate (downgrade from 7.2.0 to 2.1.0)
- Fix unused variable warnings in main.rs
- Move PathService import from domain to infrastructure
- Add missing fields to CoreServices and RepositoryServices
- Create proper service initialization in main.rs

Clean Architecture improvements:
- Domain layer no longer depends on serde framework
- Persistence concerns isolated to infrastructure layer
- TokenClaims in auth_service.rs is only exception (required for JWT)
2026-02-02 23:56:40 +01:00
dionidev e79ca8304b adding comments, moving technical documentation, improve Dockerfile, delete unuseful files 2025-03-30 14:17:09 +00:00
DioCrafts cafad0fbfd adding user authentication 2025-03-20 09:22:31 +01:00
DioCrafts d9bbd575d2 adding several features 2025-03-19 00:44:27 +01:00
root fe19bc8505 Initial commit 2025-03-17 21:28:08 +01:00