Problem definition/motivation
#3035367: Track history of subscribe/unsubscribe and proof of consent proposes to track subscriber history using entity revisions. In preparation for that we need to ensure that each subscriber operation form submit get saves confirmed and saved in one go. If confirmation is required, then there should be a single confirmation mail which covers everything.
Currently there are two exceptions to this rule.
1. There is an option per-newsletter whether subscriber email verification is required: "Opt-in/out method" = "single" or "double". If a subscription request covers two newsletters one "single" and one "double" this breaks the rule: the first newsletter will be saved immediately and the second one upon confirmation.
In many countries verification is a legal requirement, so single opt-in would not be allowed. Furthermore when you set single opt-in it also means single-opt and any unauthenticated user can alter/unsubscribe any existing subscriber. So it seems clear that single opt-in is not really a recommended or common scenario.
2. This module has a subscription setting "Use combined confirmation mails". If combined mails are not used then this breaks the rule: each newsletter will be saved separately.
This change will also help with other issues:
#3037307: Improve experience for anonymous subscribers to modify existing subscriptions - access to edit a subscription at /newsletter/subscriptions/ either needs a hash-code or it doesn't: it's not a per newsletter choice.
#1140606: Permissions Per-Newsletter: Limit subscription options by role - we need to separate the newsletter setting for confirmation from the setting for access.
Proposed solution
1. Create a new boolean site-wide setting "Require email verification of subscriptions". This matches the core setting "Require email verification when a visitor creates an account". The description should make clear that this setting is strongly recommended, and is required by privacy law in many countries.
2. Remove the per-newsletter setting "Opt-in/out method". Replace it with a new setting "Access" which initially has two values
- "Hidden": no one can set it, not even administrator
- "Default": available to administrators or any user with permission 'subscribe to newsletters'.
When fixing #1140606: Permissions Per-Newsletter: Limit subscription options by role we can add a third value "Create permission" that will generate a separate permission for that specific newsletter.
3. Remove the site-wide setting "Use combined confirmation mails", and fix the code to always use them. Remove all settings relating to single confirmation mails. This ensures we populate the 'changes' field on the subscriber. The follow on issue [##3035367] will replace the 'changes' field with code to store an entity revision.
Note that we need to keep the route "simplenews.newsletter_confirm_subscription" because it is used for unsubscribe links in newsletters.
Remaining tasks
- Write update hook.
- Consider changing
use_verificationtoskip_verification. - Consider changing
opt_inouttoaccess.
Text for release note / change record
Mostly obvious as described in "Proposed solution".
We should emphasise that sites must now fill in combined confirmation. If a site only has a single newsletter they maybe never bothered to adjust the combined confirmation emails. Also NB don't put newsletter name token in combined mails, even if there is only one newsletter being changed.
| Comment | File | Size | Author |
|---|---|---|---|
| #99 | simplenews.subscriber-updates.3066314-99.patch | 3.13 KB | adamps |
| #89 | simplenews.subscriber-updates.3066314-89.patch | 54.72 KB | adamps |
Comments
Comment #2
berdir> 1. On the SubscriptionItem, remove the "Status" property. Replace it with a
similar field on the Subscriber entity "User status".
I think that is problematic. Changes can still be per- newsletter, e.g. someone can subscribe to a newsletter, when he already is subscribed to another and then we want to track that?
Yes, having status on both is weird, but I'd rather have gone in the opposite direction and removed the global status, that always seemed weird.
Comment #3
jonathanshawI'm not sure that's true. There is the case of e.g. customers who have bought a product or signed up to a membership product of sorts. In these cases it's commonplace, generally legal, and sometimes the best UX for the person to be automatically signed up for relevant emails.
I haven't got my head around the bigger picture - I appreciate it's complex.
Comment #4
jonathanshawAnd following on logically from what I'm saying:
I don't think that email verification is necessarily only a site wide preference; it's reasonable to want it for some newsletters but not others.
But possibly this shows a simple misunderstanding on my part:
if email verification only applies when a visitor initiates the subscription through a signup form, and doesn't apply when someone is added to a newsletter programatically by other logic, then I can see that it makes sense for email verification to be site-wide.
Fundamentally, it's not the subscription that's being verified but the subscriber... You could say that if a person signs up for one newsletter, verifies, and then signs up for another we should verify the second sign up again too. But I can see the case that this is unnecessarily strict: we've already verified that the person wishes to receive emails from this site, a change in exactly what emails they want is much less of a big deal and doesn't require reverification.
You could say that does open the door to malicious extra subscribing if a bad actor knows someone is subscribed to something from a site already; but even if you require verification you've still can't solve that totally because you could have malicious extra signups triggering an annoying stream of verification requests.
Comment #5
adamps commentedThank you both for the feedback. This is exactly the sort of discussion that I was hoping for and it is a big help to get to the right solution. Don't worry I'm in no rush on this one and I won't start work until we have an agreed design.
Responding first to @jonathanshaw:
That is exactly how it is. The "Opt-in/out method" single/double applies to the case of an anonymous subscriber self-subscribing.
Yes, that's exactly what I think too.
No this issue does not make a new risk like that (and it is a step to solving the existing problem #3049356: Anon user can alter any anonymous subscription). There are two ways for an existing user wants to alter their subscription. Firstly they can click a link from a newsletter they received. Secondly they can re-authenticate - the details of which are discussed in #3037307: Improve experience for anonymous subscribers to modify existing subscriptions.
Comment #6
jonathanshawHmm. It seems like it would be very natural for a site to want it to be very easy for someone to sign up to an additional newsletter.
If I had an "Xmas countdown special offers" email I was pushing people to sign up for via a very simple form on a landing page, I'd really want it to just work regardless of whether they had signed up for some other unimportant newsletter of mine long in the past. I really wouldn't want them to have to jump through some authentication hoops.
It's possible that adding a subscription should be treated differently from modifying existing subscriptions.
This would seem to lead in the direction of per-newsletter verification, not per subscriber, as otherwise there's no way to verify the new additional sign-up.
Again, sorry for my lack of understanding of how things currently work ...
Comment #7
adamps commented@Berdir thanks for the comment. This issue and #3035367: Track history of subscribe/unsubscribe and proof of consent are the two most important ones to benefit from your knowledge.
Of course. My point is that at the moment there are two subtly different states of unsubscribe and it's mostly arbitrary which one is used - this is causing confusion and making fixing other issues more difficult.
Say there are two newsletters, A and B. If a subscriber is subscribed to A, then there is a subscription item for A with status 1. If the subscriber is not subscribed to B, then there are two possibilities: either a subscription item for B with status 0, or no subscription item for B. It just depends which form was used to sign up to A as to which case it is. We don't need to have two options, so I propose to always use the second case. Secondly we don't need to store "confirmed" state per newsletter, we can just store it per subscriber. Therefore we don't need a status field on the subscription item at all. If there is a subscription item for a particular newsletter target_id then the user is subscribed, if there isn't one, then they are unsubscribed.
Yes I agree the global status is confusing. Admins can't really understand how to act correctly with both. So I'm in favour of removing it, but it is used in some scenarios. Firstly, if a user is blocked, then they should not receive newsletters, and this flag is part of that - but it should be possible to code it differently. Secondly, if a subscriber is bouncing, then the admin may want a way to stop sending to them without just deleting them.
So perhaps we should try to combine both status fields
Comment #8
adamps commentedSure. Someone can sign up to an additional newsletter in exactly the same way as they signed up to the first one. Or even easier, they could click a link from the newsletter they are already subscribed to.
Yes to understand this issue, you need to understand the current meaning of double/single opt-in. Single means that an anonymous user can subscribe or subscribe any email address without any verification that it's their own. Often this is illegal or unwise. Double means that an anonymous user must verify their email address to subscribe or unsubscribe (or they can authenticate by clicking a link in a newsletter).
This issue proposes to remove the ability to set the opt-in per newsletter and instead it becomes a site-wide setting.
Comment #9
PhilippVerpoortDear all,
this issue has been dormant for almost a year now, and I really agree it's (1) a major blocker for many other issues for this module, and (2) has many important implications for UX and partly even for security. So I'd suggest we come to a conclusion, and crack on with filing some patches to move this module forwards.
I completely agree with @AdamPS's analysis and conclusions. The fundamental conceptual change in my opinion is that we essentially treat anonymous subscribers just like regular users but with the additional requirement to always confirm their authenticity by sending an email with an authentication link that they have to follow. By doing so we move away from authenticating individual subscriptions. I think this makes complete sense.
In summary, the proposed solution would be this:
Hope this all makes sense. I think this proposed solution will increase simplicity in code, user interface, and management.
Let me know what you think, and then I hope we can start drafting some patches for this soon. I can imagine it'll be quite a bit of rewriting. Maybe Adam is best positioned to do that, but I'm happy to test/comment/review.
Comment #10
PhilippVerpoortHere are a few more comments regarding implementation:
I believe that all code alterations should be targeted to make the newsletter-signup page and block the main point for making changes to the subscriptions. Essentially, all subscribers (users & anonymous) should be adding/removing/updating their newsletter subscriptions on that one single page (or block). This would also help with this: #3037307: Improve experience for anonymous subscribers to modify existing subscriptions
Here are the three variants the form on the page/block can take:
Access: only logged-in user (
$account->id() != 0).Display: show email widget: off. Message should be "Update the subscriptions for user {{ user.getDisplayName() }} with email address {{ user.email }}" or something.
Access: can only be accessed via a valid link. Perhaps restrict to anonymous users (
$account->id() == 0) and redirect users who are logged in or something.Display: show email widget: off. Message should be "Update the subscriptions for email address {{ anonymous_subscriber.email }}" or something.
Access: only anonymous user (
$account->id() == 0).Display: show email widget: on. Message should be "Subscribe to our newsletter!!!" or something.
Comment #11
PhilippVerpoortThe action taken when hitting the "Submit" button on this form (either the page or block) should be possible to determine using this diagram:

On that second diamond you could check whether the site-wide setting is for creating or updating subscriptions to address my point number 3. from my comment #9 above.
Comment #12
adamps commentedThanks @PhilippVerpoort.
Regarding #9, note that the issue summary already has a "Proposed solution". We can map your 5 points onto that:
Same as 1. in IS
Same as 2. in IS
True, but it's not really any change as that happens already.
No I don't think so. We must verify even if there is already an active subscription. Otherwise a random hacker to add/remove subscriptions for any existing user. I think what @jonathanshaw is saying is that we shouldn't make adding a second subscription harder than adding the first one. It's a reasonable request but not necessarily easy to achieve - the problem is that the original sign up and the new one might conflict with each other, especially if the site has extra fields like "name" on the subscriber entity.
This is already a feature - set the newsletter to "Opt-in/out method" hidden. It will remain as a feature.
Good, but I think that's a separate issue.
Yes this is quite a big change so it needs someone willing to pay for it or volunteer time (and that's not me, sorry). It's also not back-compatible so it would have to wait for a 3.x version which is not likely soon because most sites are still on 1.x not yet migrated to 2.x.
Comment #13
PhilippVerpoortOkay great, that's helpful feedback! Thanks for reading all my thoughts and responding to them in the context of what had already been planned.
It really looks like there's a clear plan for how to much this forwards, and now it just needs somebody to dedicate their time and efforts to making this happen. I'll have a look, and I'll decide if I could spare the time and potentially be that person.
Comment #14
adamps commentedThat's really great, but as I said at the bottom of the previous post, this change is not back-compatible so it would have to wait for a 3.x version which is not likely soon because most sites are still on 1.x not yet migrated to 2.x.
There's not even a branch for 3.x yet and I guess it would not be possible to commit for perhaps 1 year. The patch for this issue would affect many files so it would need a re-roll for every other commit. I think this issue should wait a little while. I guess we could mark if postponed even, except that there are a lot of outdated postponed issues and I have filtered those out in my issue query so it would make this issue low maintainer visibility.
Comment #15
PhilippVerpoortI see what you mean.
I don't think there's anything wrong with starting the work for the 3.x branch now. I don't know if it's a good strategy to postpone this issue for another year given it seems to be blocking progress on many other important issues. I think the target should definitely be to reach a stable version of the module rather than staying in beta and delaying progress unnecessarily.
But it's up to you, what ever you prefer!
I get your point about the fact that many site maintainers haven't even moved from 1.x to 2.x. Two points about this: 1) my personal experience as a site maintainer is that I also tend to postpone BC-breaking updates as much as I can, and when I do them I prefer to skip all the way to the latest version, rather than doing updates incrementally. So I'm thinking some people might actually be happy to move on to 3.x directly from 1.x? I'm thinking it might be worth offering a migration path for that, too, and that would make it more likely for people to move on. 2) perhaps there's also no good reason for people to migrate? I don't know what the difference between 1.x and 2.x was, but there's a chance people are not seeing the reason why they should go through the hassle of upgrading, when there's not too much of a gain in performance/UX/security/etc. Maybe some site maintainers are simple waiting for a stable release?
My feeling was that a lot of issues for this module are either dependent on or interrelated to this issue. For example these:
#3049356: Anon user can alter any anonymous subscription
#3037307: Improve experience for anonymous subscribers to modify existing subscriptions
#1140606: Permissions Per-Newsletter: Limit subscription options by role
#2937251: Prevent duplicate subscribers
#3037307: Improve experience for anonymous subscribers to modify existing subscriptions
I had the feeling that the new non-BC 3.x branch would be quite a big rewrite of the subscription/subscriber functionality of this module. Therefore, I thought it would make sense to incorporate as many of these interrelated issues in the rewrite as possible. All remaining issues that can be dealt with on the current 2.x branch are probably not related to the subscriber/subscription model of this module, and so would be relatively easy to merge/cherry-pick? Though, I don't have a good overview over all the existing open issues in this module, but this is a hunch.
Comment #16
adamps commentedI am glad you commented in that way. I had independently decided to come back and comment again in a more optimistic way.
If you decide that you have a firm intention to tackle this issue that I suggest you make a start now. I would ignore the tests at first and aim to get something that at least looks plausible to prove that this issue can work.
In the meantime, I propose to commit at least one non-trivial issue to 2.x Let's say we allow maximum 1 month for that.
If your patch looks like it is going to work out then I will create a 3.x branch. I will commit some accumulated coding-standards and similar tidy up issues which seem to be almost entirely affecting tests. Then you can finish off the issue on 3.x with the tidy up and tests changes.
Comment #17
PhilippVerpoortThat sounds good! Just to let you know I am playing around with the code at the moment, and trying out different things.
My plan would be this:
Does that sound sensible?
Ooph, sounds like it's going to be a lot of work!
Comment #18
jonathanshawI have been wondering if this issue would benefit from a first stage involving centralizing more logic into a subscriptionStatus service or something like that. This can help with backwards compatibility management, future maintenance, and also provides a simple point of extension that reduces the need to handle every use case in the main module.
But this is only a reaction based on the smell of the discussion so far, I haven't looked at the actual code.
Comment #19
PhilippVerpoort@jonathanshaw: That's a good point you're making, thanks for sharing your idea.
However, I think the problem is that a lot of that functionality is best placed and coded up in the subscriber entity class rather than in a service. That's because it relies on a lot of functionalities provided by the entity framework, and also because it depends heavily on what fields are stored and how they are handled.
So I think it's perhaps better/easier to handle most of the subscriber-related parts through the corresponding entity class and maybe a few other things such as the subscription field type.
Comment #20
PhilippVerpoortPlus there already exists a SubscriptionManager. I don't think it contains every important bit of the subscription management model due to the above-mentioned reasons, but it does have some of the logic in it.
Comment #21
adamps commented@PhilippVerpoort Yes I think your plan is good. I am willing to review and advise you as best I can.
I agree, I wouldn't refactor in this issue. Potentially we will at some stage in 3.x, we can see. But for now I tend to feel you should make the minimal obvious changes related to the issue you are solving. I can believe it seems a bit daunting, but I don't think it will be too bad once you get going.
The rules module doesn't currently work and you can ignore it. Although if you are doing a global search/replace I guess you might as well include rules. See #3031011: Add rules support. For the D8 upgrade path as you expect you realise, you only need to think about 2.x - Drupal automatically runs the 1.x->2.x migration then the 2.x->3.x one. For D7 migration I'm attracted to the idea that we delete them from 3.x and ask people to migrate to 2.x then upgrade to 3.x.
Comment #22
PhilippVerpoortOne quick question:
It looks like the status field on the subscriber entity is of type bool:
In
Subscriber.phpYet at the same time it looks like actually it should be int.
In
simplenews.module:and
I guess that's a bug rather than a feature? I'd suggesting changing this to an int, keep the existing states (unconfirmed, confirmed, unsubscribed) and potentially other states could be added later on.
Comment #23
PhilippVerpoortOne more questions:
Any ideas what to do about the timestamp of a subscription? I'm guessing this needs to be moved to the Subscriber entity along with the state? The timestamp is mainly used to assess if the verification code has expired, or whether to remove unconfirmed subscription in the periodic tidy-ups if their timestamp is older than some maximum allowed time period. But then do we need this additional field? The Subscriber entity also has
createdandchangedfields.I remember there was a discussion in this bug
#3035367: Track history of subscribe/unsubscribe and proof of consent
about keeping track of the history of a subscriber/subscription.
Perhaps it would be easier to track via revision API?
Just trying to work out which fields need to go where and for what purpose.
Comment #24
jonathanshawI wonder if using https://www.drupal.org/project/email_confirmer as a dependency would help. It's quite feature rich, with an audit trail of confirmations, and reasonably well maintained.
Comment #25
jonathanshawA very relevant feature of email_confirmer is that confirmations are stored, and scoped to a 'realm' like 'simplenews'.
This means opens up options like keeping the email confirmation setting per newsletter, and calling EmailConfirmerManager->confirm($email, 'simplenews') if the setting is True when processing any newsletter subscription. email_confirmer will elegantly take care of reusing previous confirmations, and only sending a new confirmation request if some reasonable time has elapsed since the last once was sent. Maybe this opens up ways for logic in simplenews to be simplified.
I'm not at all sure what email_confirmer offers to the challenges that motivate this issue, but given its potential to reduce code complexity in simplenews (which is in some sense the ultimate cause of this issue) maybe its worth considering seriously.
Comment #26
jonathanshawActually Philipp was interpreting me right.
The risk of malicious subscription is non-trivial if a previously unknown email is subscribed anonymously, so it makes sense for some/many sites to require email confirmation despite the friction it gives to the user experience. You can imagine someone finding it rather fun to subscribe all their school teachers to an edgy porn site.
But the risk of malicious subscription of an already-subscribed email is vastly less for many sites, because it requires the malicous party to know an email is already subscribed to a given site. This is both an enormously less common scenario because the relevant nowledge is rarer, and much less common because there are fewer scenarios in which it might be interesting for a malicious party to mess with the subscriptions.
Therefore it's not unreasonable for a site to weight the risk-benefit of allowing unconfirmed additional subscriptions very differently from the risk-benefit of unconfirmed new subscriptions.
Comment #27
adamps commented@jonathanshaw Thanks for the ideas.
I feel inclined to try and keep this issue focused on a single topic.
I'm nervous that the module is a beta with only 284 sites using it, last release over 2 years ago, not yet support for D9.
I feel that there are two parts to the situation.
I feel that this issue is primarily about simplifying the strategy. However it certainly would be interesting to keep in mind working towards an interface along the lines of the other module, and then we could swap out the confirmation back-end at a later stage.
Comment #28
adamps commentedI fairly dubious about that. As far as I can see, you are proposing introducing a new risk not currently present in the 2.x branch. There are potentially many devious ways of exploiting it. It might have dubious legality in one or more of the countries of the world. In any case it seems out of scope of this issue: I think here we are not trying to alter which events require confirmation. The IS has two parts:
You are making a variety of interesting suggestions but they seem beyond this scope. This issue is already going to be somewhat complex so I'm keen to be firm about keeping the boundaries tight.
Comment #29
adamps commentedRe #22, there are currently two different status settings - another part of why it's currently confusing and we hopefully make it simpler.
Subscriber entity 'status' is correctly a boolean and is very similar to the field with the same name in User.php. It is a per-subscriber setting controlled by the admin that allows to 'block' a subscriber which prevents them getting any mails and I think also disables their ability to alter settings.
The constants in simplenews.module apply to the subscription status which is present on SubscriptionItem.
The IS proposes to create a new field on Subscriber entity called 'user status' - perhaps that's not the best name, but I'm trying to indicate that the user/subscriber controls it rather than the admin. I propose that it would be an int with the 3 same values: unsubscribed (0), subscribed (1) or unconfirmed (2). Probably at first we have no code that will set the field to unsubscribed but it probably should be a possibility.
Comment #30
adamps commentedRe #23
No the second one is called
changesand it's not a timestamp but something quite different.For this issue, I believe that you should leave this field unchanged. I agree, we would remove it as part of #3035367: Track history of subscribe/unsubscribe and proof of consent, moving to use entity revisions instead.
I looked at the current usages of the timestamp field:
SubscriptionManager::tidy(). However as part of this issue you will greatly simplify that function: you can do a single query one the new "User status" field and the existing "Created" fieldsubscribe()andunsubscribe()methods. However this value is never displayed in the UI by code in this module.Comment #31
adamps commentedWhilst exploring ideas for this issue I found another security bug: #3152102: Anonymous user can alter fields of any subscriber. The existing confirmation system in this module is quite bad for security! This is yet another complication in letting unauthenticated users modify existing subscriptions. I can see two approaches
The above changes seem to belong in #3037307: Improve experience for anonymous subscribers to modify existing subscriptions and #3035367: Track history of subscribe/unsubscribe and proof of consent. If so, then what do we do here?
This issue will need to remove these lines from
SubscriptionManager::subscribe().At which point it might all just work - without needing the new field on Subscriber entity "User status". It works because the pending changes are stored in the 'changes' field for combined confirmations, and are implicit in the URL for single confirmations.
It's true, we are still doing confirmation per newsletter. However it keeps this issue reasonably well contained and we have fixed the data model in 2 useful ways. But we should bear in mind that if we stop here, then this issue alone wouldn't really finish the job.
Comment #32
adamps commentedOK, I think I have figured out the split of this issue from #3035367: Track history of subscribe/unsubscribe and proof of consent.
That should make this issue a lot simpler. It also ensures that it is clearly beneficial by itself (whereas before we were in danger of being halfway through the fixing).
Comment #33
jonathanshawAdam, I think you're doing a fantastic job at taming and keeping track of an incredibly complex module!
Comment #34
PhilippVerpoortOkay, just trying to catch up with all previous comments.
Re: #24 #25 #27
I also agree we should keep it simple, and don't add to many dependencies on other module, especially when they are not too well maintained/used. Also I still think the email validation method in the simplenews module is a bit different to the one in email_confirmer, so I don't know whether it'll be compatible.
Comment #35
PhilippVerpoortRe: #26 #28
I agree that most sites will want to stick with double validation for all changes to the subscriptions (both new and existing). Yet, given that we've already decide that we'd preserve a way to switch off these validation in the config, we might as well have a separate setting for existing subscriptions, as I believe there may be people who would prefer to have it that way. I don't think it'll add too much code complexity. That said, I also don't think it's too important to focus on right now, it can be added later on.
Comment #36
PhilippVerpoortRe: #30 #31 #32
I agree your way of splitting up the issue makes sense.
The solutions you are proposing look great (as you described in the IS of this issue and of the other one)! I was playing around with the code myself over the last few days, and I was trying different options with the revision API for the subscriber entity. I came to very similar conclusions as you did, so this gives me confidence that this is the way to go. What I like about all this is that it looks as if the whole module and code will be significantly simpler by the end.
I think we have a roadmap, which I believe you've outlined quite well in this issue (#3066314: Subscriber updates should be confirmed atomically), and this related one (#3035367: Track history of subscribe/unsubscribe and proof of consent). We first make the changes required to fix this issue (remove per-newsletter opt-in/-out setting in favour of a global one, and remove single confirmation mails in favour of always using combined). Then we move on to updating the subscriber entity and its fields, which will allow us to tackle the history tracking (#3035367: Track history of subscribe/unsubscribe and proof of consent), improve UX (#3037307: Improve experience for anonymous subscribers to modify existing subscriptions), and a whole load of other issues.
Comment #37
PhilippVerpoortThe biggest question for me now is who does what? Should I have a go at the changes needed for this issue? Or do you want to have a go at that, and I'll start looking at the changes required for #3035367: Track history of subscribe/unsubscribe and proof of consent?
Would it make sense to start a 3.x branch for these changes now? I guess what we're proposing here isn't going to be BC?
Comment #38
adamps commentedI am not going to have a go at anything - unfortunately I don't have time to write patches at the moment. I believe this issue needs to happen before #3035367: Track history of subscribe/unsubscribe and proof of consent. I would be very happy if you are willing to start on this one.
I agree I am trying to make a 3.x branch. I got confused about the new semantic versioning so there is a delay.
Comment #39
PhilippVerpoortOkay perfect!! No worries, I can have a go at this. The required changes look fairly simple anyways!
Comment #40
adamps commentedGreat thanks. New branch is working.
Comment #41
PhilippVerpoortOkay, this is a first attempt at creating a patch.
I've mostly worked on the code, and I've not done much extensive testing. I'll have to look into more testing in the next few days.
I'm sure some of the automatic tests will fail. I've fixed some of the obvious changes required in the tests, but this will require further attention later.
Also note that I haven't included an update function yet. Is that one required? It's only changes in the module config schema. Does Drupal recognise changes in the
*.schema.ymlautomatically and make updates accordingly?Feel free to comment or test but expect that it's still preliminary.
Generally, I feel I've hit the 'Delete' button quite a lot. It'd be worth double-checking things I've deleted can actually go. Similarly, there might be more things that is no longer needed and that can be removed.
Comment #42
adamps commentedExcellent it looks pretty good for a first try.
Yes. You will need to add the default for the global setting, plus fix the settings for each newsletter.
Comment #43
PhilippVerpoortNext attempt! Mostly changes to the tests.
Comment #44
PhilippVerpoortOops... looks like the previous patch I submitted was corrupted somehow. Next attempt.
Comment #45
PhilippVerpoortAh... I think I accidentally changed the underlying version, and that's why the patch doesn't apply?
Changing back to 3.x-dev and giving it another shot.
Comment #46
PhilippVerpoortOh stupid me. I wasn't patching against the 3.x HEAD. There was a commit by Adam three days ago that I missed. I did a rebase. Hopefully, this patch should at least apply now.
Comment #47
PhilippVerpoortNext attempt to fix some of the broken tests.
Comment #48
PhilippVerpoortNext attempt.
Comment #49
PhilippVerpoortNext attempt. This time I actually made some changes to the module itself since my first patch, and not only the tests as in all the other updated patches.
I'm guessing there will still be some failing tests, but I hope this new patch fixes at least some of the ones that were failing earlier.
Comment #50
PhilippVerpoortOkay, this one should resolve everything except for one failure, which I simply don't seem to be able to understand.
Comment #51
PhilippVerpoortOops. Next attempt.
Comment #52
PhilippVerpoortIt looks as if all tests are now fine except for one, which I simply don't understand.
Failures:
The first one occurs through this statement in function
testSubscribeAnonymous:I added that second assert statement because the confirmation is now always 'combined', which means it should list all the changes on that confirm page.
The second one occurs at the end of this code block in function
testSubscribeAnonymousSingle:I don't quite get that: both tests are asking to find a string, and apparently the string is in fact found — or am I misinterpreting the output? So I don't understand why it would complain.
Also for the second failure, I can confirm that the test is subscribing the anonymous user directly without confirmation when the global config variable
use_verificationis set toTRUEbecause the test a few lines below is not failing:$this->assertEquals(SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED, $subscription->status);Anyone got any ideas, give me a shout.
Otherwise, I'll now look into the upgrade path from 8.x-2.x to 3.x.
Comment #53
jonathanshaw"You have been subscribed." foundThe output can be misleading. Sometimes it describes the assertion that is failing, rather than the nature of the failure. I'm not sure there's a clear convention about from what perspective to word assertion messages.
"Subscribe to <em class="placeholder">Default newsletter</em>" foundI'd try this one as a more literal string, not wrapped in t(), in case that helps.
Sometimes you need to dump the page html out to a file and have a look at it, sadly I'm not sure Drupal provides a helper out of the box for doing that.
Comment #54
adamps commentedLooking good, thanks.
1) I guess that you should use maybe @ rather than % in "Subscribe to %newsletter" because the value isn't wrapped in em tags. - see docs
2) I would try this exact case manually and check what is printed.
Maybe better to get these tests working then let me review what's already done??
Comment #55
PhilippVerpoortNext attempt. I think I have found the solution to issue 1) in #52 but not sure yet I understand what's going wrong with 2).
Comment #56
PhilippVerpoortSome of these fails are not related to the changes I made I believe.
I'm having one final shot at issue 1) in this patch.
Comment #57
PhilippVerpoortComment #58
adamps commentedThere are a few tests that fail randomly unfortunately. They normally work again if you retest, which I just did.
Comment #59
PhilippVerpoortOk cheers, thanks!
Here comes another test.
Comment #60
PhilippVerpoortNext attempt.
Comment #61
PhilippVerpoortAnother bug fixed in the tests.
Comment #62
PhilippVerpoortOne more bug fix.
Comment #63
PhilippVerpoortSorry the previous test had a syntax error.
Comment #64
PhilippVerpoortYESSS!!!
Looks like I finally managed to resolve all the bugs in the tests! I think I actually spent 10% of my time making changes to the module, and then 90% of my time trying to sort out the tests... Anyway, the tests seem to pass all fine now, and given the amount of manual testing I have done to fix the tests I'm fairly confident that this is all working smoothly.
Next thing, we'll have to look at the migration path.
@Adam: So maybe now is a good time for you to review what I've done?
Currently, no migration path exists at all. I think Adam said he wants to have just one migration path from 8.x-2.x and remove all other (7.x / 8.x-1.x), is that right?
Comment #65
adamps commentedExcellent, I will look at this as soon as I can
Comment #66
adamps commentedFlagging for other maintainers in case they would like to review
Comment #67
adamps commentedThere is one comment for your attention please:
1.
Coding standards: missing space after if;
I don't understand why this change is needed as part of this issue as it doesn't seem related. Does it mean there is a bug somewhere else in the code requesting a newsletter token without setting the newsletter?? If we add this code does it definitely give a sensible result? Maybe the token name would be left remaining in the text??
I have made some other changes and created a new patch as summarised by these comments which are already fixed.
2. The IS "proposed solution" item 2 stated:
I'm happy to leave the variable name unchanged in the code, but I would like to improve it where visible in the UI.
3. The IS "proposed solution" item 1 stated:
4.
Delete the part relating to
$newsletter->opt_inoutwhich is related to permissions - if the user didn't have permissions they can't even reach this point. One of the benefits of this issue is that it disentangled permissions from confirmation.5. Need changes to README.txt section 12.
Comment #69
adamps commentedNot sure why the test failed when it didn't before.
I just noticed that there are 37 new coding standards warnings - probably they can mostly be fixed with the automated patch in #68.
Comment #70
PhilippVerpoortOkay great! Thanks very much for the review.
Regarding your points in #67.
1. An error popped up in those tokens, and the easiest fix was to add a
break;statement at that stage.Essentially, the problem was that the variable
$newsletteris not set in a combined confirmation email, simply because there exists no single newsletter that this confirmation email is for. In fact however, I'm also wondering whether those tokens are still needed at all? Perhaps they can still be used in the actual newsletter email somewhere, but I doubt they are still required anywhere in the subscription confirmation emails, as this should only be handled in the[combined-url]or[manage-url]tokens from now on.I think you can reproduce the error I encountered by adding the
[subscribe-url]token somewhere in the combined confirmation message, and commenting/removing my break statement. It should result in the token trying to access the non-existent$newslettervariable, and consequently in a null access warning.Perhaps is it worth removing the
[subscribe-url]and[unsubscribe-url]tokens, or replace their content with the one of the[combined-url]token for the sake of BC?((I am still convinced that, when we move on to issue #3035367: Track history of subscribe/unsubscribe and proof of consent, we can essentially remove all subscribe and unsubscribe paths, forms and tokens, and have only one single form that handles everything, along with one single token, namely the
[manage-url]token. That's because when subscription changes are managed via the revision API, there won't be any need for those forms. But we can cross that bridge when we get there.))2. OK!
3. OK!
4. I'm not sure I agree. I don't think this has anything to do with permissions. The statement you removed in the interdiff means — if I understand correctly — that you'll be now sending out confirmation emails for changes made to newsletters that are 'hidden', for which subscription should actually be handled silently.
Note that the entire
elsecode block you're talking about does not depend on the user entity, but only on the newsletter entity. So this has nothing to do with permissions, only with the newsletter entity itself.The
requiresConfirmationfunction is called every time theSubscriptionManageris asked to eithersubscribeorunsubscribea subscriber entity to a newsletter. If we proceed with your suggested changes, then doing so for a 'hidden' newsletter will result in a confirmation email, which I don't believe is intended.5. These are your suggested changes:
Is it perhaps possible that this is incorrect or misleadingly written? If I'm not mistaken, then the recipient handlers just add people to the mail spool for specific issues. However, they don't add/change/remove subscriptions to the newsletters — or am I wrong?
And finally, regarding the new fail that popped up: I'll try to take another close look at this as soon as I can. And I'll also make sure to update the coding standards warnings.
Comment #71
PhilippVerpoortA few updates:
1. Just wanted to confirm that removing those break statements in file
simplenews.tokens.incwill in fact lead to an error if the corresponding tokens are used in the combined confirmation email. I believe this bug was actually present prior to the changes suggested in this issue.Here is the stack trace:
Here is the code that results in this error:
I think adding the break statement will be fine for now. It means you can still use this token in the newsletter issue email, where an admin may want to refer to the link to unsubscribe from the particular newsletter type ("Don't want to receive emails like this any more? Click here to unsubscribe!"). At the same time, it won't cause any trouble in case somebody accidentally uses this token in the combined confirmation emails, where the variable
$newletteris not set.In the long run, as I mentioned in my previous comment, it is worth considering whether we actually want to keep all these tokens and the corresponding routes, or whether it might be easier to remove them altogether for the sake of reduced code complexity.
So long story short: I would keep those break statements in for now, and decide how to proceed with this elsewhere.
6. Regarding the failing test, I will reschedule a test for the patches in #63 and #67. I want to know if the failure has to do with any of the changes Adam introduced in the patch, or whether it might perhaps have to do with external dependencies. It looks to me like the failure arises due a formatting issue so perhaps it's a change in Swift Mailer or Core that raised this problem.
Comment #72
PhilippVerpoortOkay, that's interesting.
I think the new test of patch #63 only failed due to a bizarre random glitch arising from #2575791: Mail subject should not be run through strip_tags(). I'll confirm this by running it again. So I believe this can be ignored.
Interestingly, however, the failure in patch #67 persistently occurred in the new test whereas it did not occur in #63. So believe it must have something to do with the changes Adam introduced going from #63 to #67. Based on the interdiff, most changes that Adam introduced are just changes of labels, descriptions, and README text, so shouldn't actually change anything about the tests. I am now rewinding the actual code changes to see if it resolves the failure.
Comment #73
PhilippVerpoortOkay, I think I got it. Let's test it one more time in order to confirm I'm right.
Comment #74
PhilippVerpoortOkay, here we go again.
I created a new patch file, and this should resolve all the problems from above.
1. I have removed the
if(!$newsletter) { break; }statements. We can resolve it in a separate issue. EDIT: I've created this here. #3168355: Error when using [subscribe-url] token.2. Unchanged.
3. Unchanged.
4. I have reverted file
SubscriptionManager.phpto the version I had:Adam, please let me know if you have any objections. Please see my comment in #70.
5. I updated the README.txt file according to my comment in #70.
6. Adam, please could you explain why you made the following changes in test file
SimplenewsSubscribeTest.php?This introduced a new failure in the test. Could you explain why you would expect this assertion to be required/relevant/necessary?
7. I've run php code sniffer to deal with coding standards. This has resolved several issues (some corresponding to the changes I made but also some beyond that).
I think this should now be good to go. I'm testing this patch once more. I'm also including an interdiff to #67.
Next, we need to look at the migration path from 8.x-2.x.
Comment #75
adamps commentedGreat many thanks. I have posted a new patch to address point 4, where I still think my code is correct.
This previous code referring to
opt_inoutwas to distinguish "Double" from "Single". The fieldopt_inoutis now only for access control and it is wrong to use it to decide whether to require confirmation. This separation is a key part of what this issue is about. To help make that clearer I have added a new method NewsletterInterface::isAccessible() and altered the code to use it.The question now becomes: should
requiresConfirmation()callisAccessible()? No that is a mix-up of two orthogonal concepts. Any logged in user cannot subscribe to a hidden newsletter so cannot reach this point in the code. Any script code that subscribes users callsSubscriptionManagerInterface::subscribe()setting the$confirmparameter to control confirmations. Maybe someone wants a script that sends confirmation emails to users for a newsletter that they would not normally be able to subscribe themselves to - your version of the code would block this.I made a few other tidy ups to comments and
requiresConfirmation()because the default confirmation is global instead of per newsletter.6. The previous patch had removed a test that I recently added for a reason. I was trying to put it back. The test is supposed to check that the newsletter name is correctly HTML escaped. It's true that the newsletter name is no longer in the mail title. I had imagined that it would instead appear in the newsletter body as part of a list of the subscriptions being confirmed.
Comment #76
adamps commentedComment #77
adamps commentedSo we are getting very close. I have one concern from my testing of the last patch.
It would be fairly easy to make a mistake whilst upgrading accidentally end up with the use_verification FALSE. Either if you forget to run the database updates for some time, or if you import config created on a site still on an older software version. There is a fairly simple solution, if we change the 'sense' of the variable. We could call it 'skip_verification'.
What do you think?
Comment #78
adamps commentedFor release note / change record:
Non-BC changes to confirmation mails: sites must fill in combined confirmation. If a site only has a single newsletter they maybe never bothered to adjust the combined confirmation emails. FYI don't put newsletter name token in combined mails, even if there is only one newsletter being changed.
This is an intermediate step on the way to #3037307: Improve experience for anonymous subscribers to modify existing subscriptions. After that there will only be two confirmation mails
- Confirm new subscription
- Access link to edit existing subscription.
Comment #79
adamps commentedNeeds work for #77 and the update hook.
Comment #80
adamps commentedI committed the unrelated coding standards issues separately an rerolled this patch. It's better not to mix things up, especially for a big patch like this.
Comment #81
adamps commentedI updated the IS and added one more item to remaining tasks:
I think we potentially do need to change
opt_inouttoaccess. The IS "Proposed solution" point 2 does basically say we will do this. I had allowed it to pass in an earlier review but having tested more I don't like it for two reasons.opt_inout. Any contrib/custom code that uses the field needs to be changed. However they don't easily know that. If we change the field name then broken code is much more obvious.What do you think? Hopefully it should be a pretty speedy search and replace. We should also change the name of the related constants.
Comment #82
PhilippVerpoortThanks very much for your work and your clarifications, this is great. I agree with you on all points, looks like we can hopefully complete our work on this very soon.
Here are my answers to all your points from above:
Re: Point 4 (from #74) / #81 regarding access vs confirmations of newsletters
Thanks a lot for your clarification. I must admit I hadn't properly understood this concept previously. You are right, my additional access confirmation in
SubscriptionManager.phpwas incorrect, as it is technically possible that somebody would want to send out confirmations for newsletters that cannot be accessed through any of the forms.And I totally agree with your point in #81. Let's change the name of the
opt_inoutfield toaccess.Re: Point 6 (from #74 / #75) regarding your previous changes to
SimplenewsSubscribeTest.phpOK! So just confirming that this is fine as it is?
Re: #77
Yes, I agree with you, this an excellent suggestion. Let's change the
use_verificationfield on theNewsletterentity toskip_verification(working in the opposite way obviously). This means in case somebody forgets to run the upgrade, it will default to FALSE.Re: #78
Yup, well spotted! Concerning the newsletter name token, this is probably the same issue as #3168355: Error when using [subscribe-url] token.?
Re: #80
Good idea, thanks!
I'll try to create a new patch now!
Comment #83
PhilippVerpoortLet's give this a shot.
Comment #84
PhilippVerpoortLooks like this works. Adam, do you want to review (based on the interdiff)? I think it should all be fine now, I've incorporated the changes we discussed above.
opt_inoutreplaced byaccessuse_verificationreplaced byskip_verificationOtherwise, I think it's really getting time to look at the upgrade path? I think we need to
skip_verificationconfig setting.accessfield on every newsletter type.opt_inoutfield on every newsletter type.Anything else?
Comment #85
adamps commentedExcellent many thanks this is very close. I read the interdiff quickly and it all seems good. Yes please do start on the upgrade path and the steps you describe look good to me. I will do a more thorough final review after that.
Set back to needs work for the upgrade path.
Comment #86
PhilippVerpoortOkay, I finally managed to add the missing code for the upgrade path!
I'm uploading a revised patch, which contains the new
simplenews_update_830003function in filesimplenews.install. On top of that I found a few minor bugs in thesimplenews_demosubmodule (I suspect there may be more but perhaps it's worth resolving those manually when all major updates to 3.x have been completed). I'm also providing an interdiff.I think this is it. I gave it a shot on the dev environment of one of my D8 instances operating on simplenews 8.x-2.x. It seems to be working, and I can confirm the update function seems to be doing the right thing.
It all looks promising!
Comment #87
PhilippVerpoortOops, sorry. I somehow accidentally changed the title through some really weird autofill of my browser. Apologies.
Comment #88
PhilippVerpoortChanging status to NR.
Comment #89
adamps commentedExcellent many thanks. I did a more thorough review before committing and have uploaded a patch with some very minor changes.
1. d7_simplenews_newsletter.yml is wrong. I'm willing to let the migration code be broken in 3.x. There are no automatic tests for migration and it's time consuming to test manually. I don't feel it's right to impose that burden on the developers who give their time to solve the key bugs. People can migrate to 2.x then upgrade. Or someone who cares about migration directly to 3.x can submit a patch later on to get it working again. However we might as well have a plausible guess.
2. simplenews.install. The message seems a little too detailed, so I simplified slightly.
Comment #90
adamps commented@PhilippVerpoort Please can you review my changes in #89. If you are happy then I will commit.
Comment #91
PhilippVerpoortI agree on both points.
Re: 1) Yes sure. The update you provided seems sensible. There's indeed a good chance the migration code from 7.x is broken now as we haven't tested it thoroughly, but as you said, people can migrate to 2.x and then take it from there.
Re: 2) Sure, no problem, thanks for the revision.
Seems all good to me, looking forward to getting this submitted now.
Comment #92
PhilippVerpoortAnd yes, I have reviewed your changes based on the interdiff, and it all seems good to me.
Comment #94
adamps commentedExcellent many thanks @PhilippVerpoort. Not many developers could have fixed this issue to this high standard that you have achieved. This is one of the 3 big blockers for a stable release.
I hope that you might at some stage consider the next step, which is probably #3037307: Improve experience for anonymous subscribers to modify existing subscriptions. If you continue to fixing all 3 and then we get a stable release then I would be happy to give you credit on the project page. That would also be a good point for you could become a maintainer if you wished as you would surely know the code well.
Yes you were unlucky. The tests used single confirmation and this patch removed it. It shouldn't often be so hard, and if it happens again we can look at other options such as to disable the broken test.
Comment #95
PhilippVerpoortThanks very much, Adam. I also very much appreciate your kind words, as well as your continued support and guidance. I could not have done it without your help!
Yes great, I'd be interested to continue working on this module, and help with addressing those remaining open issues. Me becoming a maintainer for this module sounds like an interesting idea but I guess let's first get to the stable release, and then we can discuss this again. :)
Comment #96
PhilippVerpoortAnd again, somehow my browser likes inserting old values into this form...
Status is definitely fixed!!
Comment #97
adamps commentedThanks!
I wrote some better notes in the IS for #3037307: Improve experience for anonymous subscribers to modify existing subscriptions. Whilst doing that I realised that it's not essential for a stable release.
I think the key issue now is #3035367: Track history of subscribe/unsubscribe and proof of consent. I'll try to write some notes there when I get a chance.
Comment #99
adamps commentedAnother patch to fix a little bug and tidy up some unused code
Comment #101
adamps commented