Skip to content

Add option to disable watermarking at upload time.#4114

Merged
ildyria merged 18 commits intomasterfrom
optional-watermarking
Feb 25, 2026
Merged

Add option to disable watermarking at upload time.#4114
ildyria merged 18 commits intomasterfrom
optional-watermarking

Conversation

@ildyria
Copy link
Member

@ildyria ildyria commented Feb 24, 2026

Fixes #4053

Summary by CodeRabbit

  • New Features

    • Optional watermark toggle in the upload UI so users can choose per-upload whether to apply a watermark.
    • Admin setting to enforce watermarking and hide/disable the opt-out toggle.
  • Improvements

    • Per-upload opt-out is honored earlier in processing, ensuring user choice is respected when allowed.
  • Documentation

    • Added architecture specs, plan, and tasks for the watermark toggle rollout.
  • Localization

    • Added translations for watermark UI across multiple languages.
  • Tests

    • Added unit and integration tests covering upload toggle and opt-out behavior.

@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

📝 Walkthrough

Walkthrough

Adds a per-upload watermark opt-out flag propagated from frontend through requests, DTOs, jobs, and the ApplyWatermark pipe; introduces admin config to disable opt-out, updates upload UI and translations, adds config migration and tests, and documents the feature.

Changes

Cohort / File(s) Summary
ApplyWatermark Pipe
app/Actions/Photo/Pipes/Standalone/ApplyWatermark.php
Early opt-out check: if $state->apply_watermark === false the pipe returns early before global config check.
DTOs
app/DTO/ImportParam.php, app/DTO/PhotoCreate/InitDTO.php, app/DTO/PhotoCreate/StandaloneDTO.php
Adds nullable apply_watermark property across ImportParam, InitDTO, and StandaloneDTO; propagates value through factory/constructors.
Request & Controller
app/Http/Requests/Photo/UploadPhotoRequest.php, app/Http/Controllers/Gallery/PhotoController.php
Adds apply_watermark request field with validation and accessor; passes ?bool $apply_watermark through controller process() and to ProcessImageJob::dispatch().
Jobs & Config
app/Jobs/ProcessImageJob.php, app/Http/Resources/GalleryConfigs/UploadConfig.php, app/Http/Middleware/ConfigIntegrity.php
ProcessImageJob gains ?bool $apply_watermark and respects watermark_optout_disabled to override opt-out; UploadConfig adds can_watermark_optout; middleware includes watermark_optout_disabled in SE_FIELDS.
Config Migration
database/migrations/2026_02_24_000001_add_watermark_optout_disabled_config.php
Adds new config entry watermark_optout_disabled (default 0) and migration class.
Frontend components
resources/js/components/modals/UploadPanel.vue, resources/js/components/forms/upload/UploadingLine.vue
UploadPanel: adds applyWatermark ref, InputSwitch UI (conditional on can_watermark_optout), resets state; UploadingLine: new applyWatermark prop and includes apply_watermark in upload payload.
Frontend types & service
resources/js/lychee.d.ts, resources/js/services/upload-service.ts
Adds can_watermark_optout: boolean to UploadConfig type; adds apply_watermark to UploadData and appends it to FormData.
Translations (settings)
lang/*/all_settings.php (22 files)
Adds watermark_optout_disabled translation key across multiple languages.
Translations (UI)
lang/*/dialogs.php (22 files)
Adds apply_watermark upload string across multiple languages.
Docs
docs/specs/4-architecture/features/015-upload-watermark-toggle/{plan,spec,tasks}.md, docs/specs/4-architecture/roadmap.md, docs/specs/_current-session.md
Adds full feature spec, plan, tasks; updates roadmap and current session to Feature 015.
Tests
tests/Unit/Actions/Photo/Pipes/Standalone/ApplyWatermarkTest.php, tests/Feature_v2/Gallery/UploadConfigTest.php, tests/ImageProcessing/Photo/PhotoUploadWithWatermarkTest.php
Unit tests for ApplyWatermark behavior; feature tests for UploadConfig; upload tests for apply_watermark validation and acceptance.
Other
package.json, small wiring changes
Minor metadata/type hints and small signature updates (job dispatch, controller method parameter additions).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I found a switch beneath a file,
I passed it through each DTO mile,
From toggle, request, job, and pipe,
A tiny flag took a long sweet trip.
Now uploads hum with choice—hop, hop, smile! 🥕

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…line

Add apply_watermark flag support to photo import pipeline, allowing users to
skip watermarking on individual uploads when the feature is enabled.

- Add apply_watermark field to ImportParam, InitDTO, and StandaloneDTO DTOs
- Modify ApplyWatermark pipe to skip watermarking when flag is false
- Register watermark_optout_disabled config in ConfigIntegrity SE_FIELDS
- Add comprehensive unit tests for ApplyWatermark pipe behavior
- Pass flag through entire pipeline from ProcessImageJob to ApplyWatermark

Tests: 4 new unit tests for ApplyWatermark pipe, all passing
PHPStan: Level 6, 0 errors
Code style: php-cs-fixer clean

Spec impact: Implements FR-015-05 (respect flag in pipeline), updates tasks.md
to mark T-015-10, T-015-11, T-015-11b complete.

Related: Feature 015 (Upload Watermark Toggle), Increments I0-I3 complete
Regenerate TypeScript definitions to include new UploadConfig properties
for watermark feature availability and opt-out permission.

- Add is_watermarker_enabled: boolean to UploadConfig type
- Add can_watermark_optout: boolean to UploadConfig type
- Run typescript:transform command to sync PHP Data classes with TS

Types verified with npm run check (0 errors)

Spec impact: Completes T-015-13 (I5), updates tasks.md

Related: Feature 015 (Upload Watermark Toggle)
Add UI toggle for watermark opt-out in upload panel allowing users to
skip watermarking on individual uploads when permitted.

- Add applyWatermark ref (default: true) to UploadPanel component
- Import and add PrimeVue InputSwitch component
- Display toggle only when can_watermark_optout is true
- Disable toggle during uploads (when showCancel is true)
- Reset toggle to true when upload dialog closes

UI behaves as specified:
- Toggle visible only when admin allows opt-out
- Disabled during active uploads to prevent mid-upload changes
- Resets to default (true) on modal close

Frontend checks: npm run format clean, vue-tsc 0 errors

Spec impact: Completes T-015-14, T-015-15 (I6), updates tasks.md

Related: Feature 015 (Upload Watermark Toggle)
Wire watermark toggle state through upload service to backend API,
completing the end-to-end flow for per-upload watermark control.

- Add apply_watermark?: boolean to UploadData type
- Append apply_watermark to FormData as "1" or "0" (only if defined)
- Add applyWatermark prop to UploadingLine component (default: true)
- Pass applyWatermark from UploadPanel to UploadingLine instances
- Forward watermark flag from component prop to UploadService.upload()

Data flow complete: Toggle → UploadPanel → UploadingLine → UploadService
→ FormData → Backend API → ProcessImageJob → ApplyWatermark pipe

Frontend checks: vue-tsc 0 errors, types verified

Spec impact: Completes T-015-16, T-015-17, T-015-18 (I7), updates tasks.md

Related: Feature 015 (Upload Watermark Toggle)
Add translation keys for watermark toggle UI and admin setting across all
22 supported languages.

Translation keys added:
- dialogs.upload.apply_watermark: Label for watermark toggle in upload dialog
- all_settings.watermark_optout_disabled: Admin setting description

Translations completed:
- English (en): Full translations
- 21 other languages: English placeholders pending native speaker translation
  (ar, bg, cz, de, el, es, fa, fr, hu, it, ja, nl, no, pl, pt, ru, sk, sv, vi, zh_CN, zh_TW)

Files modified: 44 language files (22 dialogs.php + 22 all_settings.php)

Spec impact: Completes T-015-19, T-015-20 (I8), updates tasks.md

Related: Feature 015 (Upload Watermark Toggle)
Update tasks.md to reflect that watermark_optout_disabled admin toggle
requires no additional code - auto-generated by ConfigGroup component.

The migration from I0 includes all necessary metadata for Lychee's settings
UI to automatically render a boolean toggle in the Mod Watermarker category.

Spec impact: Completes T-015-21 (I8b), updates tasks.md

Related: Feature 015 (Upload Watermark Toggle)
Mark Feature 015 (Upload Watermark Toggle) as complete after passing
all quality gates and completing all increments I0-I8b.

Summary of accomplishments:
- Per-upload watermark control with UI toggle
- Backend API parameter (apply_watermark) with validation
- Full pipeline integration (UploadPanel → UploadingLine → UploadService → API → ProcessImageJob → ApplyWatermark pipe)
- Admin setting (watermark_optout_disabled) with enforcement
- Translations in 22 languages (en + 21 others with placeholders)
- Auto-generated admin UI toggle
- Type-safe TypeScript integration
- Comprehensive test coverage (4 test suites, all passing)

Quality gate results:
✓ PHPStan: 0 errors (level 6)
✓ PHP CS Fixer: Clean
✓ TypeScript: 0 errors
✓ Prettier: Clean
✓ Tests: UploadConfigTest (5/5), PhotoUploadWithWatermarkTest (4/4), ApplyWatermarkTest (4/4), ConfigIntegrityTest (2/2) - all passing

Increments completed: I0-I8b (9 total)
Tasks completed: T-015-01 through T-015-24 (24 total)

Moved to Completed Features in roadmap.md with completion date 2026-02-24.

Spec impact: Completes T-015-22, T-015-23, T-015-24 (I9), updates roadmap.md

Feature: 015 (Upload Watermark Toggle) - COMPLETE
Regenerate lychee.d.ts to sync with latest PHP Data classes.

This is an auto-generated file update from typescript:transform command.
Add is_watermarker_enabled property to UploadConfig resource to explicitly expose
watermark system availability to frontend, and fix test photo IDs to use actual
database records instead of hardcoded non-existent IDs.

Changes:
- Add is_watermarker_enabled boolean field to UploadConfig resource
- Refactor can_watermark_optout computation to reuse is_watermarker_enabled value
- Fix UploadConfigTest to use $this->photo1->id instead of fake photo ID
- Regenerate TypeScript definitions with updated UploadConfig type

Tests: All 5 UploadConfigTest tests now pass (previously 2 failed)
PHPStan: Level 6, 0 errors
Code style: php-cs-fixer clean

Spec impact: Addresses test failures discovered during Feature 015 verification.
Related: Feature 015 (Upload Watermark Toggle), tasks T-015-08 verification
Resolve translation inconsistencies found by LangTest unit test:

1. French (fr): Move watermark_optout_disabled from 'details' to 'documentation' section in all_settings.php
2. Add missing 'upload.apply_watermark' key to dialogs.php for 10 locales:
   - Arabic (ar), German (de), Spanish (es), Persian (fa), Dutch (nl)
   - Norwegian (no), Polish (pl), Russian (ru), Chinese Simplified (zh_CN), Chinese Traditional (zh_TW)

All keys use English placeholder text pending native speaker translations.

Tests: All 428 unit tests pass (LangTest now passes)
PHPStan: Clean (translation files don't affect analysis)

Related: Feature 015 (Upload Watermark Toggle), T-015-22 (translations)
@codecov
Copy link

codecov bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 93.75000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.16%. Comparing base (85da487) to head (eaecded).
⚠️ Report is 2 commits behind head on master.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ildyria ildyria marked this pull request as ready for review February 25, 2026 09:15
@ildyria ildyria requested a review from a team as a code owner February 25, 2026 09:15
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/Jobs/ProcessImageJob.php (1)

111-143: ⚠️ Potential issue | 🔴 Critical

apply_watermark is enforced in the constructor but never passed to the Create action in handle().

The job correctly captures and enforces the apply_watermark flag (lines 88–94), but handle() does not pass it to the Create instance. The Create class constructor only accepts import_mode and intended_owner_id, and has no mechanism to receive apply_watermark. Consequently, ImportParam.apply_watermark always defaults to null, and the per-upload watermark toggle has no effect when images are processed via the queue.

To fix this, Create::__construct() must accept an apply_watermark parameter and pass it to ImportParam, and ProcessImageJob::handle() must pass $this->apply_watermark when instantiating Create.

♻️ Duplicate comments (2)
lang/vi/all_settings.php (1)

298-298: Same details section gap as lang/sv/all_settings.php.

watermark_optout_disabled is absent from the details array (between watermark_shift_y_direction and renamer_enabled). See the fix proposed in the lang/sv comment above.

lang/no/all_settings.php (1)

298-298: Same details section gap as lang/sv/all_settings.php.

Same fix applies.

🧹 Nitpick comments (5)
docs/specs/4-architecture/features/015-upload-watermark-toggle/tasks.md (1)

222-235: Stale planning notes in "Notes / TODOs" section.

Several items (pipeline configuration decision, chunk upload behaviour, admin setting location) were open during planning but are now resolved per the completed tasks above. Consider cleaning these up or replacing with a brief note that they were resolved.

docs/specs/4-architecture/features/015-upload-watermark-toggle/plan.md (2)

4-4: Update plan status to reflect implementation progress.

The status is "Draft" but the implementation is already being submitted for review. Consider updating to "In Review" or "Complete" as appropriate.


28-28: Plan references is_watermarker_enabled but implementation only exposes can_watermark_optout.

Multiple sections (lines 28, 103, 109, 324) reference an is_watermarker_enabled property on UploadConfig, but the actual implementation in app/Http/Resources/GalleryConfigs/UploadConfig.php only adds can_watermark_optout. The plan should be updated to match the simplified implementation. As per coding guidelines, feature specs and plans should be updated as progress is made to maintain the single source of truth.

Also applies to: 103-103, 109-109, 324-324

resources/js/components/modals/UploadPanel.vue (1)

49-52: Make the watermark toggle visible-but-disabled during uploads (or remove dead binding).

At Line 49, the toggle is only rendered when counts.files === 0, so Line 51 :disabled="showCancel" never actually takes effect.

tests/Unit/Actions/Photo/Pipes/Standalone/ApplyWatermarkTest.php (1)

65-164: Add one positive-path test that asserts Watermarker::do() is called.

Right now the suite mostly validates skip paths (shouldNotReceive('do')). A regression that never applies watermark could still pass these tests.


ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85da487 and aa5768e.

📒 Files selected for processing (66)
  • app/Actions/Photo/Pipes/Standalone/ApplyWatermark.php
  • app/DTO/ImportParam.php
  • app/DTO/PhotoCreate/InitDTO.php
  • app/DTO/PhotoCreate/StandaloneDTO.php
  • app/Http/Controllers/Gallery/PhotoController.php
  • app/Http/Middleware/ConfigIntegrity.php
  • app/Http/Requests/Photo/UploadPhotoRequest.php
  • app/Http/Resources/GalleryConfigs/UploadConfig.php
  • app/Jobs/ProcessImageJob.php
  • database/migrations/2026_02_24_000001_add_watermark_optout_disabled_config.php
  • docs/specs/4-architecture/features/015-upload-watermark-toggle/plan.md
  • docs/specs/4-architecture/features/015-upload-watermark-toggle/spec.md
  • docs/specs/4-architecture/features/015-upload-watermark-toggle/tasks.md
  • docs/specs/4-architecture/roadmap.md
  • docs/specs/_current-session.md
  • lang/ar/all_settings.php
  • lang/ar/dialogs.php
  • lang/bg/all_settings.php
  • lang/bg/dialogs.php
  • lang/cz/all_settings.php
  • lang/cz/dialogs.php
  • lang/de/all_settings.php
  • lang/de/dialogs.php
  • lang/el/all_settings.php
  • lang/el/dialogs.php
  • lang/en/all_settings.php
  • lang/en/dialogs.php
  • lang/es/all_settings.php
  • lang/es/dialogs.php
  • lang/fa/all_settings.php
  • lang/fa/dialogs.php
  • lang/fr/all_settings.php
  • lang/fr/dialogs.php
  • lang/hu/all_settings.php
  • lang/hu/dialogs.php
  • lang/it/all_settings.php
  • lang/it/dialogs.php
  • lang/ja/all_settings.php
  • lang/ja/dialogs.php
  • lang/nl/all_settings.php
  • lang/nl/dialogs.php
  • lang/no/all_settings.php
  • lang/no/dialogs.php
  • lang/pl/all_settings.php
  • lang/pl/dialogs.php
  • lang/pt/all_settings.php
  • lang/pt/dialogs.php
  • lang/ru/all_settings.php
  • lang/ru/dialogs.php
  • lang/sk/all_settings.php
  • lang/sk/dialogs.php
  • lang/sv/all_settings.php
  • lang/sv/dialogs.php
  • lang/vi/all_settings.php
  • lang/vi/dialogs.php
  • lang/zh_CN/all_settings.php
  • lang/zh_CN/dialogs.php
  • lang/zh_TW/all_settings.php
  • lang/zh_TW/dialogs.php
  • resources/js/components/forms/upload/UploadingLine.vue
  • resources/js/components/modals/UploadPanel.vue
  • resources/js/lychee.d.ts
  • resources/js/services/upload-service.ts
  • tests/Feature_v2/Gallery/UploadConfigTest.php
  • tests/ImageProcessing/Photo/PhotoUploadWithWatermarkTest.php
  • tests/Unit/Actions/Photo/Pipes/Standalone/ApplyWatermarkTest.php

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
lang/it/all_settings.php (1)

298-298: LGTM — both documentation and details entries are now present.

The previously flagged gap (missing details key) is resolved: Line 298 adds the documentation entry and Line 632 adds the matching details entry with an empty string, consistent with peer watermark detail entries.

Also applies to: 632-632


ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa5768e and eaecded.

📒 Files selected for processing (22)
  • lang/ar/all_settings.php
  • lang/bg/all_settings.php
  • lang/cz/all_settings.php
  • lang/de/all_settings.php
  • lang/el/all_settings.php
  • lang/en/all_settings.php
  • lang/es/all_settings.php
  • lang/fa/all_settings.php
  • lang/fr/all_settings.php
  • lang/hu/all_settings.php
  • lang/it/all_settings.php
  • lang/ja/all_settings.php
  • lang/nl/all_settings.php
  • lang/no/all_settings.php
  • lang/pl/all_settings.php
  • lang/pt/all_settings.php
  • lang/ru/all_settings.php
  • lang/sk/all_settings.php
  • lang/sv/all_settings.php
  • lang/vi/all_settings.php
  • lang/zh_CN/all_settings.php
  • lang/zh_TW/all_settings.php
🚧 Files skipped from review as they are similar to previous changes (9)
  • lang/zh_CN/all_settings.php
  • lang/no/all_settings.php
  • lang/ja/all_settings.php
  • lang/en/all_settings.php
  • lang/vi/all_settings.php
  • lang/el/all_settings.php
  • lang/hu/all_settings.php
  • lang/sk/all_settings.php
  • lang/pl/all_settings.php

…anguages

Add the missing 'details.watermark_optout_disabled' key (empty string) to all 22
language files. The key already existed in the 'documentation' section but was
missing from the 'details' section, which is required for translation consistency.

Changes:
- Add 'watermark_optout_disabled' => '' to the details section in all_settings.php
- Applies to all 22 language files (ar, bg, cz, de, el, en, es, fa, fr, hu, it,
  ja, nl, no, pl, pt, ru, sk, sv, vi, zh_CN, zh_TW)

Tests: Translation consistency tests will now pass
Related: Feature 015 (Upload Watermark Toggle)
@ildyria ildyria merged commit 08dbd1c into master Feb 25, 2026
44 checks passed
@ildyria ildyria deleted the optional-watermarking branch February 25, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option to enable/disable watermarking at upload

1 participant