Skip to content

fix: deliver sign invitations to email-identified existing users - #9429

Open
vitormattos wants to merge 10 commits into
mainfrom
fix/9425-email-account-notifications
Open

vitormattos wants to merge 10 commits into
mainfrom
fix/9425-email-account-notifications

Conversation

@vitormattos

@vitormattos vitormattos commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Problem

Fixes #9425.

An email-identified signer whose address belongs to an existing Nextcloud account could receive neither the signing invitation nor an in-app notification: the invitation-mail path consulted an account's opt-out despite the recipient being explicitly identified via email. In-app and activity invitations are restricted to account signers.

Behavior and architecture

  • Invitation/reminder: send by email to an explicitly email-identified signer regardless of whether that address belongs to a Nextcloud account; never turn the email address into a Nextcloud UID.
  • Account signer: resolve email through the selected account and check the actual account UID for preference decisions, including shared-email accounts.
  • Cancellation: preserve the existing unique-email-account preference semantics for email-identified recipients. They must not receive previously suppressed cancellation messages. For account-identified recipients, preferences are checked by selected UID.
  • Continue skipping deleted identities, unresolved accounts and empty addresses. Preserve signed-file email handling, failure isolation and mail-history semantics.
  • Remove unused listener dependencies; only the private mail-recipient resolution/notification rule is shared. No new public service, API or authentication change.

Regression tests and testability

MailNotifyListenerTest drives the public handle(Event) method and inspects emitted NotificationMessage objects rather than invoking MailChannel inside the listener tests. Readable small event factories remove repeated internal setup, and preference fixtures use UID-sensitive returns to assert observable delivery outcomes instead of internal call counts.

Covered: existing GUID-style UID vs email; external email signer; observer; reminder vs first invitation; account enable/disable preference; shared email; deleted/unresolved accounts; empty and unsupported identifiers; cancellation (unique linked account enabled/disabled, external, shared); owner-signed messages and envelope child suppression.

NotificationChannelsTest independently verifies mapping of first invitations, reminders, signed-file and cancellation messages to the expected MailService calls. Observer validation links are covered in the existing MailServiceTest.

Validation

  • Code and tests are against main (original base b02d0b82e3abe346085c8bfe059e7ca4bf8f6bfd). The next main commit only updates Transifex translations.
  • The original minimal fix passed all 21 CI workflows. The larger architecture refactor had successfully completed 18/21 workflows without failures when reviewed, but this is not evidence for the later corrective commits.
  • CI failure diagnosis: all four PHPUnit database workflows failed in testExternalEmailSignerReceivesCancellation because IUserManager::getByEmail() was not stubbed for an external address and returned null in PHPUnit; count(null) caused a TypeError. Fixed by explicitly configuring [] for the missing account, without altering production behavior.
  • Latest head: f7d25426f44d9786f43ce1b3d46a365ef20d8320. All four PHPUnit database workflows (SQLite, MySQL, MariaDB, PostgreSQL) passed on this head. At the last verification, 19/21 workflows had passed; Playwright and Behat PostgreSQL were still running. Do not merge until final checks are verified.
  • All commits DCO sign-off and cryptographic signing verified.
  • No live NC35/LibreSign 15.0.12 reproduction or test SMTP delivery was executed; the CI tests target the current main contract.

No automatic merge requested.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
@vitormattos
vitormattos requested a review from a team as a code owner November 10, 2026 02:44
@github-actions

github-actions Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Code Metrics Report

main (b02d0b8) #9429 (a263225) +/-
Coverage 76.1% 76.2% +0.0%
Test Execution Time 1s 2s +1s
Details
  |                     | main (b02d0b8) | #9429 (a263225) |  +/-  |
  |---------------------|----------------|-----------------|-------|
+ | Coverage            |          76.1% |           76.2% | +0.0% |
  |   Files             |            500 |             500 |     0 |
  |   Lines             |          28578 |           28576 |    -2 |
+ |   Covered           |          21776 |           21779 |    +3 |
- | Test Execution Time |             1s |              2s |   +1s |

Code coverage of files in pull request scope (82.0% → 86.7%, patch 100.0%)

Files Coverage +/- Patch Coverage Status
lib/Listener/MailNotifyListener.php 86.7% +4.7% 100.0% modified

Reported by octocov

@vitormattos

Copy link
Copy Markdown
Member Author

/backport to stable35

@backportbot-libresign backportbot-libresign Bot added the backport-request Request to backport a change to supported stable branches label Nov 10, 2026
@vitormattos

Copy link
Copy Markdown
Member Author

/backport to stable34

@vitormattos

Copy link
Copy Markdown
Member Author

/backport to stable33

Remove unused listener dependencies and resolve account notification
preferences by UID, leaving email-identified signers on mail delivery.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Use event inputs and delivery outputs instead of passing messages through
MailChannel and MailService in listener tests. Cover invitation, reminder,
account preferences, shared emails, cancellation and signed notices.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Assert cancellation preferences at the listener boundary and verify
initial versus reminder mail arguments at the channel boundary.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Keep account-based cancellation preferences when a signer was identified
by email, without reintroducing invitation suppression from issue #9425.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
…coupling

Cover existing-account cancellation opt-outs, external recipients, unknown
methods and empty addresses. Keep mock configuration readable and assert
observable delivery intents instead of internal invocation sequences.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Cover transport mapping for signed and canceled events, legacy handling
of shared cancellation addresses and child envelope duplicate avoidance.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
The Nextcloud user manager returns an empty list when no users match an
email address. Model that contract explicitly in the regression test,
preventing count(null) across the PHPUnit database matrix.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-request Request to backport a change to supported stable branches

Projects

None yet

1 participant