Problem/Motivation
If you have a single page load (or in my case, hook_cron() invocation) that's triggering multiple group_notify events, users can get duplicate notifications for the same group content.
This is because of how the protected NotifyGroupNode::$recipients array is handled.
group_notify_notify()gets the content plugin:$plugin = $entity->getContentPlugin();group_notify_notify()calls$plugin->addRecipient($member);once for each group member.group_notify_notify()calls$plugin->sendNotification($params);, which inspects$this->recipientsfor the list of users to notify.
If this only happens once in a given request, all's well. But when a 2nd node is updated in the same request, we get into trouble. Step #1 above returns a link to the same plugin object. It's already got all the recipients from the initial notification. But step #2 happily adds them again, and step #3 means we get multiple emails for the 2nd node.
If there was a 3rd node being updated in the same request, everyone would get 3 emails.
If the nodes are in different groups, it's even worse, since it means that notification emails leak content to users who aren't members of the group. E.g. node 1 from group A goes out to everyone in group A. Then node 2 is updated in group B, all users of groups A and B see the emails for node 2. Folks in both groups see it as duplicates. But folks only in group A see it as access bypass.
Steps to reproduce
- Install group + group_notify (8.x-1.5 or 8.x-1.x-dev).
- Create a group type configured to use group_notify for a specific node type.
- Create two groups.
- Subscribe a user to both groups.
- Either programmatically create a node for each group in a single page load, or in my case, update both nodes in the same page load to set them to be published and use #3164688: Forced notification when a node is created or updated via API (not via UI forms) to get group_notify to send notifications.
The user should get 2 emails (one from each group). In reality, they'll get 3.
Proposed resolution
Clear out the recipients before computing who gets notified for a given message.
Remaining tasks
Do it.- Tests?
- Reviews / refinements.
- Commit.
User interface changes
Nope.
API changes
Maybe we should add NotifyGroupNode::clearRecipients() so group_notify_notify() has a way to clear recipients for each distinct message?
Or we could always clear $this->recipients inside NotifyGroupNode::sendNotifications(). Probably that's better (and no API change).
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | 3170625-2.patch | 685 bytes | dww |
Comments
Comment #2
dwwHere's the approach where we just clear
$this->recipientsat the end ofGroupNotifyNode::sendNotification(). This seems simpler then exposing aclearRecipients()method and making it the caller's responsibility to get this right.Thoughts?
Thanks!
-Derek
Comment #3
dwwAttaching the patch would help. ;) Sorry for the noise.
Comment #4
gregcube commentedWow. Good catch! Yes, lets not rely on the caller to clear the recipients array. I'm fine with your approach. Will commit shortly. Thanks again.
Comment #6
gregcube commentedComment #7
dwwGreat, thanks!
Cheers,
-Derek