After several other issues that lead to higher complexity in form handling this issue is about reducing complexity of those processes.
What we want is a clear separation for user edit forms and manager edit forms.
Erik also stated this in
- #208016: Better newsletter signup block with checkbox or radio button option for multiple newsletters
- #579202: Exposing & updating language settings
One question might be for an admin after that change:
Why can't i assign internal newsletters to the user (on the user profile)..
It is NOT that logic that an admin will have more options if he edits the user via admin interface instead. Most other drupal modules act differently.

See the next Post for an inventory.

Please complete your opinions and directives to make this cleanup happen ASAP. 6--2 will then be a clean base for new features such as multilanguage, multi signup and more.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

miro_dietiker’s picture

As a first step here are all current occurences of form creation snippets in simplenews plus multisignup. Lines are missing by intention to being able to compare the similarities as compact as possible.

Any input about how to make these uniform best are much appreciated.

BLOCK SIGNUP
for anonymous / user

@simplenews.module
function template_preprocess_simplenews_block
drupal_get_form('simplenews_block_form_'. $tid);
hook_forms simplenews_block_form_$tid
$form = simplenews_block_form()

[BLOCK MULTISIGNUP]
for anonymous / user
http://drupal.org/node/208016
http://drupal.org/project/simplenews_multisignup

@simplenews_multisignup.module
function simplenews_multisignup_block()
_simplenews_multisignup_block()
$rendered_form = drupal_get_form('simplenews_subscription_manager_form', NULL, 'simplenews_multisignup');

PAGE SIGNUP
for anonymous / user

hook_menu  @simplenews.module
function simplenews_menu
newsletter/subscriptions
drupal_get_form simplenews_subscription_manager_form
@simplenews.subscription.inc

REGISTER USER
for anonymous only

hook_user  @simplenews.module
function simplenews_user
op='register'
$form = array(...);

USER PROFILE SIGNUP
for user only

hook_user  @simplenews.module
function simplenews_user
@simplenews.subscription.inc
$form = _simplenews_subscription_manager_form($subscription);

ADMIN SINGUP
for admin

admin/content/simplenews/users/edit/%
drupal_get_form simplenews_admin_users_form
@simplenews.subscription.inc
$form simplenews_subscription_manager_form(, $snid)
$form = _simplenews_subscription_manager_form($subscription);
miro_dietiker’s picture

After a long discussion around this topic we've finally came to the following situations with limited complexity that should be implemented separately.

Note that primarily we need to get rid of the _manager_ functions and make clean candidates for the separated cases. At least _manager_ should only get used for internal admin tasks.

Single Newsletter Public Block

A form to be shown in a block representing a single Newsletter. It will change behaviour regarding $user login state (anonymous subscriber VS user subscription state).

Multiple Newsletter Public Block

The Page callback or the multiple signup block, to subscribe to n newsletters.
Like the single block, depending the login state it will show anonymous subscriptions or $user subscription information.

Account Form

A form to be shown in user context only - showing $account subscription data.
Depending the $account permissions it will show the options available.
Additionally if an admin $user visits the page he will be able to edit $account admin settings.

Admin Form

A Form to be visit with admin privileges showing a subscriber that is either anonymous or has a $account. The subscribers' state/permission has no effect to the form options variety.

Sutharsan’s picture

This is largely what I had in mind too :)

Single Newsletter Public Block
This block should be kept simple by default. i.e. more simple than it currently is. I'm not a big fan of options, we should reduce the number of options in the admin interface but keep the variables availabe in the template file. Perhaps use a simple template by default and include an example template with all features enabled.

Multiple Newsletter Public Block
I welcome this block in simplenews 'core'. The admin should have the ability to select the newsletters which will be listed in the block. (Some sites have hundreds of newsletters)

Account Form
What you describe is the current functionality. We should discuss further what to do with email language setting.

Admin Form
The above form gives the admin a way to edit individual accounts. Admin forms should be focused on centralized subscription maintenance and mass maintenance operations. The current admin forms lack a page/form to display/edit all subscriber settings per user. Your description matches this form.

If we agree on this level we can detail each form with wire frames. When (re)writing the code we can start high level too after which each form can be coded separately.

khaled.zaidan’s picture

Assigned: miro_dietiker » khaled.zaidan
FileSize
10.47 KB

Done the rewriting/separation for the account form and admin form.

I still didn't work on the blocks yet.

miro_dietiker’s picture

Thank you, khaled for this start.
In general this is the right direction.

I'd prefer some more clearness in function/form naming.
My suggestion is:
Start all forms with: "simplenews_subscriptions_"
Then add a postfix depending the case.

  • Single Newsletter Public Block
    Postfix: _public_one
  • Multiple Newsletter Public Block
    Postfix: _public_all
  • Account Form
    Postfix: _account
  • Admin Form
    Postfix: _admin
khaled.zaidan’s picture

FileSize
24.56 KB

Added the multiple signup block (with separate code from other forms). Made sure to check the permissions.

miro_dietiker’s picture

Status: Active » Needs work

Thanks for the update! Here's a first review.

+++ simplenews.module	13 Jun 2010 17:12:53 -0000
@@ -276,7 +276,7 @@
+    'page arguments' => array('simplenews_subscriptions_account_form'),

The name _account seems not to represent the situation since this form will also allo subscriptions for anonymous users. So regarding my words this is the _public_all case

+++ simplenews.module	13 Jun 2010 17:12:53 -0000
@@ -960,66 +966,93 @@
+        $form['simplenews_multi_signup_block_help'] = array(
+          '#type' => 'textarea',
+          '#title' => t('Help text'),
+          '#default_value' => variable_get('simplenews_multi_signup_block_help', t('Select the newsletter(s) to which you want to subscribe or unsubscribe.')),
+          '#description' => t("Use this option to change the help message displayed above the form."),
+        );
...
+        $form['simplenews_block_'. $delta]['simplenews_block_m_'. $delta] = array(
+          '#type' => 'textfield',
+          '#title' => t('Block message'),
+          '#size' => 60,
+          '#maxlength' => 128,
+          '#default_value' => variable_get('simplenews_block_m_'. $delta, t('Stay informed on our latest news!')),
+        );

What's the difference between the Block message and the Help text?
BTW: This implementation also will result in trouble to have clean translations.

+++ simplenews.module	13 Jun 2010 17:12:53 -0000
@@ -960,66 +966,93 @@
+      if ($delta == 0 && user_access('subscribe to newsletters')) {
         $block = array(
...
+      else {

I was looking for a location where a permission check occurs in this case. Is it really missing?

+++ simplenews.module	13 Jun 2010 17:12:53 -0000
@@ -1367,6 +1400,143 @@
+    '#description' => t('Select the newsletter(s) to which you want to subscribe or unsubscribe.'),
...
+    $form['subscriptions']['#title'] = t('Manage your newsletter subscriptions');

There's no "you" in an admin case. It's much more a "users'" case.

+++ simplenews.module	13 Jun 2010 17:12:53 -0000
@@ -2785,3 +2959,29 @@
+  module_load_include('inc', 'simplenews', 'simplenews.subscription');
+  $rendered_form = drupal_get_form('simplenews_subscriptions_multisignup_block_form');

As you see here, form creators are usually in simplenews.subscription.inc.
Please move all corresponding functions into that file.

Looking forward to the next step. May be, sutharsan can also review this step.

khaled.zaidan’s picture

Status: Needs work » Active
FileSize
28.43 KB

- Form name changed to _public_all.
- 'Help Text' and 'Block Message' turned out to be the same, will use 'Block Message' for all.
- Translation issue: removed the use of the t function from the form editing. Now it's only used when displaying.
- Permission check is now done inside callback that builds the html for the multisignup block.
- Wording in the admin's form is fixed.
- Moved the form related functions to the inc file.

khaled.zaidan’s picture

Status: Active » Needs review
miro_dietiker’s picture

Looks cool to me.
There's a single trailing space ...
But much more we need quality reviews now. We'll need some days to push this issue.
Awaiting further responses.

Sutharsan’s picture

I have reviewed the patch and added my comments in the file. File is attached.

roball’s picture

Status: Needs review » Needs work
Thomas_Zahreddin’s picture

Assigned: Unassigned » khaled.zaidan
FileSize
13.59 KB

see # 15, new patch

miro_dietiker’s picture

Many thanks, thomas.

Additionally
We need better i18n support for things like variable simplenews_block_m_multiple.

Note the submitted patch -13 doesn't contain all parts of _8 ... but some. So it can't be applied.
Can you resubmit your changes please?

Thomas_Zahreddin’s picture

Assigned: khaled.zaidan » Unassigned
FileSize
35.45 KB

patch against dev-Version of 2010-07-11

uses patch of #8 (since #11 was not possible to apply with the tool i used)

and corrects the format of the code.

miro_dietiker’s picture

This is great, thx thomas.
So the comments from sutharsan #11 are not yet considered.
Still some work needed.

Thomas_Zahreddin’s picture

Assigned: khaled.zaidan » Unassigned
FileSize
58.98 KB

patch Coder-clean
(one false positive with Coder 6.x-2.0 beta1)

patch against dev-Version of 2010-07-11

uses patch of #8

manually integrated the comments of #11

and corrects the format of the code.

miro_dietiker’s picture

OK i've totally reworked the code since i expected to do some things differently and in addition considered Sutharsans comments.
Find below a patch containing the direction.
It is completely untested and will need some work to complete. I feel it makes the codebase much more clean.

Any inputs about the current state?

miro_dietiker’s picture

Status: Needs work » Needs review
FileSize
42.1 KB

Attached a new version. This time tested and against the latest updated 6--2.
This time it needs review.

NicoH’s picture

I've tested the patch and it seems to work.

Found two issues already present:
#884338: Spool duplication on node resave
#884348: Unsubscribed users not filtered in newsletter subscriptions page

There's one typo in simplenews.module @1081

            'subject' => check_plain($newsletters[$delta]),
should be
            'subject' => check_plain($newsletters[$delta]->name),
miro_dietiker’s picture

Status: Needs review » Fixed

OK cool.
Since everything else seems to work and i'd like much more to proceed with the separated forms i pushed this change into the codebase.

Committed to 6--2 including the tiny issue from #20, thx.
If something's wrong with this, please provide new patches against latest cvs.

miro_dietiker’s picture

Status: Fixed » Patch (to be ported)

I think this needs port to make 7.x cleaner.

miro_dietiker’s picture

Assigned: Unassigned » miro_dietiker
Category: task » bug
Priority: Normal » Critical

Apologies, the user profile subscription form is broken in current code.
Somehow 3 people missed testing is before we committed.
This is currently critical for 6--2 to work. I'm working on it.

miro_dietiker’s picture

Corrected the account form.
There was a specific uncertainity because we could use after form creation in hook_user op=form to save data:
A: store things using hook_user op=update in category=newsletter - where no specific validation occurs (this is a special case not following regular FAPI workflow
B: use $form['#validate'] and $form['#submit'] for form submission and leave hook_user op=update unused

To be as similar as possible to all other form subscription submission implementation i decided to switch to B.
I hope we're not introducing some specific issue not covered with this new method.

Patch applied, provided attached. From my point of view the 6--2 release should now be at least as clean as ever before (which means we'll push it into production to get more feedback). Please help testing! :-)

miro_dietiker’s picture

Assigned: miro_dietiker » Unassigned

unassigning from me here. :-)

roball’s picture

Does #23 that mean that the current dev version is broken or has #24 fixed this already? If it is supposed to work now I think the status should be better set to "needs review".

miro_dietiker’s picture

Version: 6.x-2.x-dev » 7.x-1.x-dev
Category: bug » task
Priority: Critical » Normal

6--2 is corrected (as far as i know) - regarding all things that additionally caming up.
This is no more a bug report but a task to push D7 version to a similar result.
If there's something new coming up, please bring this back to 6--2 as a bug report.

roball’s picture

Version: 7.x-1.x-dev » 6.x-2.x-dev
Category: task » bug
Priority: Normal » Critical
Status: Patch (to be ported) » Needs work

Please let's try to ensure this issue is fixed on 6.x first. I have updated to the latest 6.x-2.x-dev from today which was critically broken due to the changes in the simplenews_subscriptions_account_form() function. Please bear in mind that you are altering Drupal core's complete user account profile page and not just subscriptions! Thus $form['#redirect'] should be FALSE, as core would behave. Now any changes from profile and subscription fields at user/[UID]/edit will simply be ignored!!!

miro_dietiker’s picture

Status: Needs work » Postponed (maintainer needs more info)

roball
note that we're first checking for $category == 'newsletter'
This means we're altering the form only for the newsletter tab.

I don't get what's currently broken on your side. All things i could edit in user/$myuserid/edit are persisted very well without any hassle. Again: What's wrong with that?

Do you think e.g. we should reside on the newsletter tab and leave the redirect to a custom module if needed?

roball’s picture

Here I explain the behaviour in detail with corresponding 4 attached screenshots:

(1) I am on my user edit page (user/1/edit) *without* having the critical simplenews_subscriptions_account_form() function being active. I have deactivated that function by simply adding "return;" to the function's first line. So simplenews is not interfering with Drupal's default behaviour. All the fields within the "Personal information" fieldset are coming from core's profile.module. To reproduce, so please also activate that module, define some fields and assign some values.

(2) After changing some profile.module fields and clicking the [ Save ] button, I see the "The changes have been saved." message on top of the (same) user edit page. The changes have in fact be done. All fine. This is to demonstrate how it should work.

(3) This is the same screen as (1), but now with the original "simplenews.subscription.inc" file, meaning that the critical simplenews_subscriptions_account_form() function is now fully active. You can see the active function by the fact that a "Current newsletter subscriptions" fieldset has been added. But there is NO "newsletter tab" - core's profile edit page has been altered. Then I changed only one field - the profile.module's Country field, from Austria (AT) to Bahamas. I completely leaved the subscriptions settings untouched.

(4) After clicking the [ Save ] button, I am no longer on the same edit page (as it would be without the module), but instead I have been redirected to the User view page. Bad. And, I no longer see the message "The changes have been saved." (as it would be without the module), but "Your newsletter subscriptions have been updated." instead. Worse. I didn't change anything with my newsletter subscriptions, so why am I bothered with this confusing message? But the worst thing is that my Country field change has been ignored - the country still remains to Austria (AT).

roball’s picture

Do you still need more info to be aware of this situation?

miro_dietiker’s picture

Status: Postponed (maintainer needs more info) » Needs review
FileSize
3.13 KB

Attached a patch that does some cleanup.
I'm still not sure we should do it that way, but it's already much cleaner than before.

Please review and report.

Mac Clemmens’s picture

I am still getting the same error.

It is being triggered by the user_profile_form_validate() function in user.pages.inc. (function below for your reference)

It does not pass the check array_intersect(array_keys($form_state['values']), array('uid', 'init', 'session') because $form_state['values'] contains the key uid.

It doesn't seem necessary to have the uid key, because the user information is already loaded into the [_account] key. Do you have any idea why or how the uid key would find its way into $form_state['values']?

Here's the output of $form_state during the first #validate function.

Array
(
    [storage] => 
    [submitted] => 1
    [values] => Array
        (
            [newsletters] => Array
                (
                    [1523] => 1523
                )

            [uid] => 10
            [_category] => newsletter
            [_account] => stdClass Object
                (
                    [uid] => 10
                    [name] => mac
                    [pass] => /*removed for posting on drupal.org*/
                    [mail] => /*removed for posting on drupal.org*/
                    [mode] => 0
                    [sort] => 0

...

function user_profile_form_validate($form, &$form_state) {
  user_module_invoke('validate', $form_state['values'], $form_state['values']['_account'], $form_state['values']['_category']);
  // Validate input to ensure that non-privileged users can't alter protected data.
  if ((!user_access('administer users') && array_intersect(array_keys($form_state['values']), array('uid', 'init', 'session'))) || (!user_access('administer permissions') && isset($form_state['values']['roles']))) {
    watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING);
    // set this to a value type field
    form_set_error('category', t('Detected malicious attempt to alter protected user fields.'));
  }
}

miro_dietiker’s picture

I finally checked it again and it worked.
Did you really download a version containing this fix? If you download -dev you might need to wait some hours to find it rebuilt representing the latest fixes.

Mac Clemmens’s picture

I think I figured it out.

In the function simplenews_subscriptions_account_form() in simplenews.subscription.inc

There is an unecessary line that trips the security alert. (around line 74)

$form['subscriptions']['uid'] = array('#type' => 'value', '#value' => $account->uid);

It just needs to be commented out.

Then, a few lines later, in the submit function simplenews_subscriptions_account_form_submit(),
The line that depended on ['uid'] needs to get the uid from the ['_account'] variable instead.

So, delete this line:
$account = user_load(array('uid' => $form_state['values']['uid']));

and replace it with:
$account = user_load(array('uid' => $form_state['values']['_account']->uid));

and it works. (For me anyway.)

I am concerned about the usage of $edit['uid'] in the insert function of simplenews.module, but I don't know enough about the module to make any informed recommendations. I just hope this snippet will save others some grief.

Patch attached.

Mac Clemmens’s picture

Hey miro_dietiker,

Actually I was going to build a patch and found the CVS version is out of sync with the latest -dev. It is fixed in the latest CVS.

I also took a look at HEAD and it appeared to be an old copy from February. Is that for D7 or something?

roball’s picture

I forgot to say that the problem described in #30 only appears when the "One page profile" module is enabled. Now, with the latest 6.x-2.x-dev (2010-Sep-17), the redirecting problem has been solved, but the other two problems still remain (regarding "The changes have been saved." message and not saving any user profile changes). The workaround for the time being is just to disable the "One page profile" module, so "My newsletters" appears as an own tab under user/[UID]/edit. Should I file a separate issue for this?

miro_dietiker’s picture

roball,
Onepageprofile might need to explicitly integrate simplenews for one page support...

Due to the method used in 6.x-2.x to build the form this might not be supported automagically.
Either we should switch to "the" standard way and solve side effects on a different way - or put the integration into the module. Note that switching the integration to the current way solved many issues as a side effect which would come up again once we switch back... (this is about hook_user op=form)

roball’s picture

Hm, maybe you could discuss how your module should best work together with One page profile with its maintainer - aidanlis. The release notes of One page profile 6.x-1.10 mentions "Provides better integration with other modules", so I guess it should be possible.

Thanks for considering One page profile module support.

kruser’s picture

subscribe

Simon Georges’s picture

Apparently, there is an issue between Simplenews and One Page Profile since some time already : #615262: Empty fields with simplenews module. Anyway, maybe it's time to fill a new issue and to close this one, so it's clearer for everybody involved what it's left to do ? @miro_dietiker, what do you think ?

miro_dietiker’s picture

Version: 6.x-2.x-dev » 7.x-1.x-dev
Status: Needs review » Patch (to be ported)

Yes please.
The rewrite we did seems to be clean. Please relate to this issue for completeness.
Pushing this issue to 7.x port now.

roball’s picture

Priority: Critical » Normal

Update of priority.

miro_dietiker’s picture

Assigned: Unassigned » DrupOn

Assigning

brenes’s picture

Hmm I stepped into the same problem. I have got Simplenews 6.x-2.0-alpha1 along with the one page profile Module installed and the problems are as described by roball in comment #37: No changes are saved on the edit profile page and the misleading message "The changes have been saved.". Any further Ideas how to get both modules working together?

miro_dietiker’s picture

webchick’s picture

Tagging. (Hope this isn't incorrect.)

Berdir’s picture

Status: Patch (to be ported) » Needs review
FileSize
44.46 KB

Attaching a first patch that seems to work when testing manually and also passes all tests locally, checking with testbot. A manual test from someone interested in this feature would also be great, I will however commit pretty soon I think.

Note that I started off with the 6.x-2.x version of simplenews.subscriptions.inc and updated that for 6.x-2.x, except some unrelated parts like the confirmation forms. So this should contain all the follow-up patches in this issue.

Also, it is possible that this patch fixes double confirmation for authenticated users, I think I have seen an issue about that and when looking at the code it is rather obvious that it didn't work. Basically, function simplenews_subscriptions_page_form_submit() created a faked account object with only the mail property and then later on check if $account->uid is set. Which never is...

miro_dietiker’s picture

Status: Needs review » Fixed

Great. Tested all possible forms manually.

Note that there was a case missing and led to Error 500.
admin/people/simplenews/users/edit/$uid

Here was a function, namely simplenews_subscriber_update($subscription, $data); that was inexisting.
Changed the code to object notation and simplenews_subscriber_save($subscription);

Committed, pushed. Do we need some additional test?

miro_dietiker’s picture

Assigned: DrupOn » Unassigned

Ah, unassigning. :-)

miro_dietiker’s picture

And needed to add a second commit, found some issue more.

@@ -674,7 +674,7 @@ function simplenews_subscriptions_admin_form($form, &$form_state, $snid) {
...
- '#default_value' => $subscription->language->language,
+ '#default_value' => $subscription->language,

Berdir’s picture

Tests for the multi-sign up block would be nice and also for the bugs you find.

Basically, if possible, we should try to create a test case for each found bug. Because then we can be sure that this bug will not occur again.

miro_dietiker’s picture

Adding notes to test code about the additionally needed cases.

Status: Fixed » Closed (fixed)
Issue tags: -D7 stable release blocker

Automatically closed -- issue fixed for 2 weeks with no activity.