Skip to content

feat(sharebymail): dispatch BeforeShare*MailSentEvent before each mail send#277

Open
printminion-co wants to merge 21 commits into
masterfrom
feat/sharebymail-before-mail-sent-event
Open

feat(sharebymail): dispatch BeforeShare*MailSentEvent before each mail send#277
printminion-co wants to merge 21 commits into
masterfrom
feat/sharebymail-before-mail-sent-event

Conversation

@printminion-co

Copy link
Copy Markdown

Summary

Upstream-ready extract of IONOS PR #262, prepared for contribution to nextcloud/server.
Introduces a PSR-14 event dispatched immediately before every mailer->send() in
ShareByMailProvider, so listeners can intercept/replace native SMTP delivery for share-by-mail
notifications.

  • New apps/sharebymail/lib/Event/ classes: AbstractBeforeShareMailSentEvent (base) +
    BeforeShareMailSentEvent, BeforeSharePasswordMailSentEvent, BeforeShareNoteMailSentEvent
  • Dispatch points in sendEmail(), sendPassword(), sendPasswordToOwner(), sendNote();
    markMailHandled() skips native send (no silent fallback)
  • $templateData refactor + fix so createPasswordSendActivity no longer fires when a listener
    suppresses the mail
  • Test coverage + composer autoload entries

Scope / cleanup vs PR #262

  • Fork-only content dropped: the apps-custom/nc_ionos_processes submodule bump and the
    hand-edited generated autoload noise. Diff is apps/sharebymail/** only.
  • Commits reworded to Conventional Commits (no IONOS(...)/HDNEXT markers); rebased onto current
    master. Drift fixes: dropped an unused import; replaced withConsecutive() (removed in
    PHPUnit 10) with a willReturnCallback idiom; autoload entries in ksort order.

Verification (dev container)

  • ./autotest.sh sqlite apps/sharebymail/tests/ShareByMailProviderTest.phpOK (40 tests, 440 assertions)
  • composer cs:check clean on the changed files
  • psalm skipped (container PHP 8.3.6 < required 8.3.16)

Follow-ups

  • ⚠️ The refactor(sharebymail) commit is missing a Signed-off-by — will be added + force-pushed.
  • External nextcloud/server PR to be opened separately by the human contributor (AI policy).

AI assistance

Branch prepared with AI assistance (cherry-pick, reword, drift-conflict resolution). Underlying
code is human-authored (PR #262).

Your Name and others added 15 commits June 23, 2026 15:20
Signed-off-by: Your Name <you@example.com>
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
Signed-off-by: Carl Schwan <carlschwan@kde.org>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
…sion before failing on increased permissions

Signed-off-by: provokateurin <kate@provokateurin.de>
…ptimization

feat: Fetch groups in batch in getUserGroups
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
…nteraction-file-delete-create-before-increase

fix(files_sharing): Fail on sharing file with create or delete permission before failing on increased permissions
…x-shell

feat(core): header-anchored combobox shell for unified search
…ngle event

Signed-off-by: provokateurin <kate@provokateurin.de>
fix: webhook payload for system tag events
By default only 25 group objects are loaded. If a user is assigend to a
group, that isn't loaded yet, we only show the gid instead of the
displayname.

Assisted-by: Copilot:gpt-5.4
Assisted-by: ClaudeCode:claude-sonnet-5

Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
@printminion-co printminion-co force-pushed the feat/sharebymail-before-mail-sent-event branch from c09ac83 to f2b7041 Compare July 9, 2026 14:25
@printminion-co printminion-co requested a review from Copilot July 9, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds PSR-14 events in apps/sharebymail that are dispatched immediately before each native mailer->send() call in ShareByMailProvider, allowing listeners to suppress/replace SMTP delivery for share-by-mail notifications (share link, password, and note mails).

Changes:

  • Introduce BeforeShare*MailSentEvent classes (with a shared abstract base) to carry the prepared IMessage and recipients and allow suppressing native sending via markMailHandled().
  • Dispatch these events from ShareByMailProvider::sendEmail(), sendPassword(), sendPasswordToOwner(), and sendNote(), skipping native send when handled.
  • Update unit tests and app-local composer autoload classmaps to include the new event classes.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
apps/sharebymail/lib/ShareByMailProvider.php Dispatch new events before each mail send and skip native send when handled; refactor template data arrays.
apps/sharebymail/tests/ShareByMailProviderTest.php Extend tests to assert event dispatch and updated template data; add tests around “mail handled” behavior for password flows.
apps/sharebymail/lib/Event/AbstractBeforeShareMailSentEvent.php Add common event base carrying share, recipients, and rendered message plus “handled” flag.
apps/sharebymail/lib/Event/BeforeShareMailSentEvent.php Add event for share-link notification mails.
apps/sharebymail/lib/Event/BeforeSharePasswordMailSentEvent.php Add event for password notification mails (recipient + owner cases).
apps/sharebymail/lib/Event/BeforeShareNoteMailSentEvent.php Add event for note-update notification mails.
apps/sharebymail/composer/composer/autoload_static.php Register new event classes in the app-local composer autoloader map.
apps/sharebymail/composer/composer/autoload_classmap.php Register new event classes in the app-local composer classmap.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +28
/**
* @param string[] $resolvedEmails validated recipients
*/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fixed in commit fix(sharebymail): fix docstring and add isMailHandled tests for sendEmail and sendNote. The @param docstring now reads "resolved recipient addresses (not guaranteed to be validated)" to accurately reflect that call sites like sendNote() and sendPasswordToOwner() do not validate addresses before dispatching.

Comment on lines +411 to +415
$event = new BeforeShareMailSentEvent($share, $emails, $message, $templateData);
$this->eventDispatcher->dispatchTyped($event);
if ($event->isMailHandled()) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Added testSendEmailDoesNotSendWhenMailHandledByListener in commit fix(sharebymail): fix docstring and add isMailHandled tests for sendEmail and sendNote. The test sets up a listener that calls markMailHandled() on the dispatched BeforeShareMailSentEvent and asserts mailer->send() is never called.

Comment on lines +585 to +589
$event = new BeforeShareNoteMailSentEvent($share, [$recipient], $message, $templateData);
$this->eventDispatcher->dispatchTyped($event);
if ($event->isMailHandled()) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Added testSendNoteDoesNotSendWhenMailHandledByListener in commit fix(sharebymail): fix docstring and add isMailHandled tests for sendEmail and sendNote. The test marks BeforeShareNoteMailSentEvent as handled via a listener and asserts mailer->send() is never invoked.

chore(jobs): write proper documentation for job:history

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@printminion-co printminion-co force-pushed the feat/sharebymail-before-mail-sent-event branch from 3391f42 to d928ae7 Compare July 9, 2026 15:31
kesselb and others added 3 commits July 9, 2026 20:14
…n-users-list

Show group display name when the group object is not loaded yet
…n/allow-multiple-resources-and-receivers

refactor(Interaction): Allow multiple resources and receivers in a single event
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
…ateData variables

Extract the inline array literals passed to each createEMailTemplate() call
into named $templateData variables. For sendNote(), which previously passed no
data array, add a minimal array so all four send methods are consistent.

Zero behaviour change — $templateData is passed straight through to
createEMailTemplate() with identical contents.

Signed-off-by: Misha M.-Kupriyanov <kupriyanov@strato.de>
…ch mail send

Dispatch a typed PSR-14 event immediately before every mailer->send() call
in ShareByMailProvider so that external listeners can intercept and replace
Nextcloud's native SMTP delivery.

Event hierarchy:
  AbstractBeforeShareMailSentEvent (base: share, resolvedEmails, message,
    markMailHandled / isMailHandled)
  ├── BeforeShareMailSentEvent   – sendEmail()
  ├── BeforeSharePasswordMailSentEvent – sendPassword() + sendPasswordToOwner()
  └── BeforeShareNoteMailSentEvent – sendNote()

Each concrete class holds its own typed $templateData (psalm array-shape)
and exposes named getters (getSenderUserId(), getFileName(), …) instead of
a generic getMailData(): array<string,mixed>.  This avoids defensive
is_string() / null guards in listeners.

$templateData reuses the array already passed to createEMailTemplate(), with
one extra key added for sendEmail(): senderUserId (the raw user ID, distinct
from the display name stored under 'initiator').

The native mailer->send() is skipped when a listener calls markMailHandled().
If the listener's own send throws, the exception propagates and the native
send is also skipped — no silent SMTP fallback.

sendEmail() and sendPassword() are flattened from nested
if (!isMailHandled()) { ... } pyramids to early-return style.

createPasswordSendActivity() in sendPassword() and sendPasswordToOwner() now runs
only when the mail was actually sent: it moved inside the isMailHandled() early
return, so a listener that suppresses the SMTP send no longer produces a false
password-share activity entry.

Signed-off-by: Misha M.-Kupriyanov <kupriyanov@strato.de>
@printminion-co printminion-co force-pushed the feat/sharebymail-before-mail-sent-event branch from d928ae7 to edc6c9c Compare July 10, 2026 07:21
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.