Scenario 1:
- Create 2 anon subscribers with email AA and BB
- Admin edits subscriber AA to email BB
Scenario 2:
- Create an anon subscriber with email AA
- Create a registered user subscriber with email BB
- User changes email from BB to AA.
Scenario 3:
- Create a registered user with email AA but no subscriptions
- Create an anon subscriber with email BB
- Admin changes email from BB to AA.
Critical priority because of potential data corruption.
Proposed resolution
Scenario 1
Add a UniqueField constraint on the subscriber - see #7.
Scenario 2
When the email address changes for a user Entity, delete any existing subscriber with that email address.
As a separate matter, it is obviously desirable when using Simplenews to verify user change of email. There is a core patch #85494: Use email verification when changing user email addresses. There's also a module email_confirm, but currently only D7.
Scenario 3
We can allow this, but need to set the uid field in the subscriber to point to the user that now matches.
Existing duplicates
Could create hook_update to remove any existing duplicates. In addition to the scenario described above, they could be from #3031018: Account form creates duplicate subscribers. However it's not going to be easy to be sure which ones to remove. I propose to skip this, or at least defer to a separate issue.
Original summary
Firstly, thanks for the effort and it's nice to see the D8 version of Simplenews taking shape.
We've noticed one issue whereby it appears possible to create multiple subscribers with the same email address.
It seems perhaps the email address should have some unique constraint?
In the D7 version, there was a unique key between the uid and mail but appears not the case in the D8 version
describe simplenews_subscriber;
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| uuid | varchar(128) | YES | UNI | NULL | |
| status | tinyint(4) | YES | | NULL | |
| mail | varchar(254) | YES | | NULL | |
| uid | int(10) unsigned | YES | MUL | NULL | |
| langcode | varchar(12) | YES | | NULL | |
| changes | longtext | YES | | NULL | |
| created | int(11) | YES | | NULL | |
+----------+------------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)Just wanting to check the reasoning on that one, and if ok to apply a unique constraint to the simplenews_subscriber email from your perspective.
Please advise, thanks
Comments
Comment #2
adamps commentedComment #3
adamps commentedComment #4
andrewbelcher commentedI would very much like to see this! Duplicate subscribers cause a real issue, especially when you consider GDPR/other privacy initiatives as people unsubscribe, but the duplicate is left active.
The alternative to making the database use a unique constraint is to add a field constraint, as User does in core. That way any form that attempts to change email addresses will hit that as part of entity validation and show an error.
Comment #5
adamps commented@andrewbelcher yes this is a good discussion to have.
I don't see them as alternatives - we can and maybe should do both. Look at the issue summary I have identified 3 steps. Step 3 is about user experience, step 2 is about enforcement/avoidance of bugs.
Yes, but it's more complex than the user mail constraint.
Comment #6
adamps commentedComment #7
adamps commentedScenario 1
We can add a constraint on the subscriber:
This blocks the scenario giving a clear error message. It seems reasonable to enforce that the admin cannot make 2 anonymous subscribers with the same email.
Scenario 2
We could add a constraint on the user by means of
hook_entity_base_field_info_alter(). It would presumably need to be a new custom validator but fairly easy to write copying from UniqueFieldValueValidator but looking into the subscriber entity type rather than the current entity type.However as mentioned in #5 this is not necessarily an acceptable restriction. Perhaps we could try to make the constraint ignore unsubscribed subscribers?? Then print a message telling the user they can unsubscribe their other account then try again?
Comment #8
adamps commentedComment #9
adamps commentedComment #10
adamps commentedScenario 2
I propose that when editing a user email address, if there is an existing subscriber then that subscriber should be deleted. Then at least we avoid corrupted a database with duplicates.
As a separate matter, it is obviously desirable when using Simplenews to verify user change of email. There is a core patch #85494: Use email verification when changing user email addresses or a module email_confirm.
Comment #11
adamps commentedComment #12
adamps commentedComment #13
adamps commentedComment #14
adamps commentedComment #15
jonathanshawRe #7
It seems unacceptable to block the user from changing their email in this way.
Re #10:
+1. I can't see a better solution.
Comment #16
adamps commentedComment #17
adamps commentedThe fix here gets tangled up with #3049356: Anon user can alter any anonymous subscription. However that one is blocked on the complex fix #3035367: Track history of subscribe/unsubscribe and proof of consent. Many issues are tangled up in each other and we need to be practical or nothing will get committed. So I've deleted some pretty broken code about setting the subscriber status, with a @todo to replace it with correct code as part of the other issue.
Comment #19
adamps commentedComment #21
adamps commentedComment #23
adamps commentedComment #25
adamps commentedComment #27
jonathanshawAFAICS the subscriber status will always be TRUE because simplenews_user_update always calls $subscriber->fillFromAccount().
It might be worth a comment that what we're really concerned with here is the possibility that the email has changed.
As I remember, this will solve an unrelated need identified in my project. Yay.
Comment #28
adamps commentedComment #30
adamps commentedYay finally! The syncing code is extremely delicate - hopefully won't have to change it again for a long while. We still need new tests for the scenarios that we are fixing.
Re #27 thanks for the review
You are correct. However the comment will be correct after the @todo has been completed and #3049356: Anon user can alter any anonymous subscription has been fixed. Right now the state of that function is rather arbitrary, but I thought I might as well leave the function as close to the final correct code as I could.
Thanks I added several comments.
Comment #31
adamps commentedPlan to commit after adding tests.
Comment #33
adamps commentedNew patch with tests.
The code moved from SubscriptionsFormBase to SubscriptionsBlockForm was necessary to allow the second bullet in this test to work. It's OK to move that code because since #3037307: Improve experience for anonymous subscribers to modify existing subscriptions, that's the only form that allows anonymous users.
Comment #34
adamps commented@jonathanshaw Ready to commit if it looks good to you.
Comment #36
adamps commentedGreat thanks - another stable release blocker fixed many thanks for your help