Skip to content

[3.0] Keep every recipient of a personal message, not just the last one - #9461

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/pm-received-recipients
Open

[3.0] Keep every recipient of a personal message, not just the last one#9461
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/pm-received-recipients

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

pm_recipients holds one row per person a PM was sent to. Received::$loaded is keyed accordingly — first by the PM, then by the member:

self::$loaded[$this->id][$this->member] = $this;

Received::loadByPm() built its return value with only the PM as the key:

foreach (self::queryData($selects, $params, $joins, $where) as $row) {
    $loaded[(int) $row['id_pm']] = new self($row);
}

so each row overwrote the one before it, and a PM came back with exactly one recipient — whichever the database handed over last. (The cache branch above it does the same thing, looping over the member-keyed list only to flatten it.)

Two things go wrong from there.

You cannot open a PM you received alongside somebody else. PM::canAccess() walks that list looking for the current member, and if that member was not the one that survived, it isn't there. Sending a PM to two members and opening it from the recipient's inbox:

?action=pm;f=inbox;pmid=4
before 403, "You are not allowed to access this section"
after 200

And the recipient list is wrong. PM::format() builds recipients from the same list, so the sent folder named one recipient of a PM that went to several:

To
before testmember
after admin, testmember

number_recipients is that count, so reply_to_all was also hidden on every multi-recipient PM.

The fix keys the list by recipient as well, which is the shape PM::format() and the popup already read it with (foreach ($this->received as $member => $received_copy)), and picks out our own copy in applyActions() rather than looping over everyone's — those are our labels, not theirs.

Verified afterwards that the eleven pages of the PM area and the quote form all still render with an empty smf_log_errors.

Labelling a PM with more than one recipient needs #9460 as well, which fixes the update behind it; this change alone gets as far as reaching it.

Issues References (Fixes|Related|Closes)

Related: #9460

pm_recipients holds one row per person a PM was sent to, and
Received::$loaded is keyed accordingly, first by the PM and then by the
member. Received::loadByPm() built its return value with only the PM as
the key, so each new row overwrote the one before it and a PM came back
with a single recipient - whichever the database handed over last.

Two things go wrong from there. PM::canAccess() walks that list looking
for the current member, so opening a PM you received alongside somebody
else was "You are not allowed to access this section" unless you happened
to be last. And PM::format() builds the recipient list from it, so the
sent folder named one recipient of a PM that went to several, and the
reply-to-all button was hidden because the count said one.

Keys the list by recipient as well, which is the shape PM::format() and
the popup already read it with, and picks out our own copy in
applyActions() rather than labelling everybody's.

Signed-off-by: Mathias Albert <mathiaspapealbert@hotmail.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@jdarwood007 jdarwood007 added this to the 3.0 Alpha 6 milestone Aug 9, 2026
@jdarwood007 jdarwood007 added the PM label Aug 9, 2026
@albertlast albertlast mentioned this pull request Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants