This module provides light-weight subscribe/unsubscribe functionality for mailing lists running on a Mailman mailing list server. It provides:
- A simple administrative page for specifying mailing lists that the site will suppot.
- A simple page for users to subscribe or unsubscribe from lists.
- The Mailman server does not need to be local to the same server on which Drupal runs, but if it is, the module can use the 'sync_members' utility of mailman to synchronize all members of a Drupal role with membership of a mailing list (requires Drush).
In short, this module is not a management utility for Mailman. It simply provides mechanisms for allowing users to subscribe or unsubscribe to a mailing list.
Cloning the code
As per the reviewer comments below. Mailman Simple was merged into another project and renamed Mailman Subscribe. The updated project page is here: https://www.drupal.org/node/36863
To clone the 7.x-1.x branch:
git clone --branch 7.x-1.x http://git.drupal.org/project/mlist.git
For reference, the original project page for mailman simple is here: https://www.drupal.org/sandbox/spficklin/1917302
How to Test
For reviewers testing this module, you can use any Mailman list you know of. When you configure the module, provide the subscribe and unsubscribe emails which are usually of the form [list_name]-subscribe@[domain] and [list_name]-unsubscribe@[domain]. When you test subscription to the list, the module will send an email subscription request to the mailing list which will in turn send you an email to complete registration to the list. You can delete the email to terminate the registration process (you won't be subscribed to the mailing list) but by receiving the email it shows the module is working.
List of reviewed projects
https://www.drupal.org/node/2209529#comment-8957869
https://www.drupal.org/node/2290647#comment-8958031
https://www.drupal.org/node/2298389#comment-8960121
Similar Modules
There are no other Drupal modules that provide a simple quick interface to support subscription or unsubscription of a user from a Mailman mailing list. The following describes how Mailman Simple differs from similar modules:
The Mailman Manger module provides a robust set of management tools for the Mailman server, whereas, the "Mailman Simple" module is intended to be light-weight to simply provide subscribe/unsubscribe functionality. Mailman Simple will help sites that want to easily provide a form for subscription/unsubscription to a mailing list and do not have the permission or perhaps the desire to manage the mailing lists via the Drupal site. The following modules also support Mailman but do so by extending Mailman Manager: User mailman register, Mailman Groups
The Mailman Mailing List Management Wrapper integrates with the command-line tools of Mailman but has not been updated since Drupal 4.
The mailman mailing list admin module has also not been updated since Drupal 4.
The Mailman Mailing List Management Wrapper module has not been updated since Drupal 5. It also provided wrappers for the command-line tools of Mailman.
The Mailman 2 module also provided management of a remote Mailman mailing list using XML-RPC. but it has also not been updated since Drupal 5.
Comments
Comment #1
PA robot CreditAttribution: PA robot commentedThere are some errors reported by automated review tools, did you already check them? See http://pareview.sh/pareview/httpgitdrupalorgsandboxspficklin1917302git
We are currently quite busy with all the project applications and we prefer projects with a review bonus. Please help reviewing and put yourself on the high priority list, then we will take a look at your project right away :-)
Also, you should get your friends, colleagues or other community members involved to review this application. Let them go through the review checklist and post a comment that sets this issue to "needs work" (they found some problems with the project) or "reviewed & tested by the community" (they found no major flaws).
I'm a robot and this is an automated message from Project Applications Scraper.
Comment #2
spficklin CreditAttribution: spficklin commentedPareview warnings/errors resolved.
Comment #3
spficklin CreditAttribution: spficklin commentedComment #4
spficklin CreditAttribution: spficklin commentedComment #5
spficklin CreditAttribution: spficklin commentedComment #6
er.pushpinderrana CreditAttribution: er.pushpinderrana commented@spficklin, thanks for your contribution!
I have manually reviewed your module and below are my assumptions:
1. You have defined all callback functions in
mailman_simple.module
file, I think you should include.inc
file and defined all callback function there.2. You have called following function on number of places but at some places you forget to check count.
Correct Code:
Incorrect Code:
Pointer lines: 548 and 572.
3. On line number 121, you used
db_select
but before iterating you missed to check count. Check count first to avoid unnecessary notices.As I analyzed your code, at most of places you have used forloop without checking whether variable contains values or not. Please do this at all places, one more thing add some more comment to following code.
Looks like you are moving loop for same array twice, not sure why it can;t be solved using one loop.
Please fix these.
Again thanks for your contribution!
Comment #7
gwprod CreditAttribution: gwprod commented@er.pushpinderrana
I have inspected his code, and there is no reason to call count within the form submit function. He calls count in the form, because if there are no items, he displays some markup saying there are no items. Within the submit function, he already knows there are items, because you can't submit the form without buttons, which require there were items. But even if he didn't know that, it isn't necessary to check if there are list items, as nothing is sent if there aren't. His code is not 'incorrect'.
On line 121, it is unnecessary to check the count before iterating over the array, since an array with 0 elements is not iterated by foreach.
Comment #8
spficklin CreditAttribution: spficklin commentedHi er.pushpinderrana,
Thanks for your review. I have:
1) Moved callback and helper funtions into a new include file. The .module file now only contains the Drupal hooks.
2) I agree with gwprod, in cases were there is no check of the length of the list it is because the list is used in a "for each" loop and that loop will not iterate if no items exist in the list. So, there shouldn't ever be any errors from that. I left the code as it was.
3) The same is true for the previous line 121 where the result of a db_select is used in a "for each" loop. If there are no elements in the list, the loop will not iterate
4) Good catch on the double looping. I have reduced it to a single loop and simplified that code.
5) I have added more comments. Thanks for noticing.
The code has been pushed, I re-ran pareview.sh and is ready to review again.
Comment #9
gwprod CreditAttribution: gwprod commentedmailman_simple_subscribe_form_validate does not implement hook_validate(). hook_validate() is from node api, not form api.
likewise, there is no hook_submit
in mailman_simple_callbacks.inc (which would be more appropriately named mailman_simple.callbacks.inc)
on line 418, you shouldn't concatenate onto t(), but instead use a replacement.
is link a form api element type on line 426?
It might be a better idea in mailman_simple_get_lists() to use db_select, and use IN with a list of the user's roles.
In mailman_simple_show_lists()
This
is preferable to this
Comment #10
gwprod CreditAttribution: gwprod commentedThose issues are fairly minor, I think, so I am RTBCing this.
Comment #11
spficklin CreditAttribution: spficklin commentedThanks for your review, pwprod! I have made the following changes:
1) Fixed the comments for the submit, validate functions to not say they are implementations of the node form hooks. Thanks or noticing.
2) I have renamed the callback file as: mailman_simple.callbacks.inc
3) Fixed the concat for t() on line 418
4) A "link" is part of the Render API. There is an open issue regarding where to properly document it: https://www.drupal.org/node/1190658. But it seems appriorate to use it in a form, and it works :-)
5) I think you're right, the code would be a bit more simple. I wanted, however, to show all the lists, regardless of the role if the user had the 'manage mailing lists' permission. That would complicate the SQL so I thought it would be easier to check the roles or permission of each list in the code.
6) Fixed the theme('table', ...) call.
Comment #12
mpdonadioAs far as I can tell, all of the comments above have been about the 7.x-1.x branch, but there is also a 6.x-1.x branch. Has this been reviewed? Is this branch part of the application?
Comment #13
spficklin CreditAttribution: spficklin commentedHi mpdonadio,
The 6.x-1.x branch is not needed, but was left over from the original version of the code. It has been removed, only the 7.x-1.x branch remains. Not sure what status to use... I switched it back to RTBC
Thanks
Comment #14
mpdonadioThanks for the clarification. RBTC is appropriate, as that was the status before I requested some clarification.
Comment #15
mpdonadioAssigning to myself for my next review.
Comment #16
mpdonadioAutomated Review
Review of the 7.x-1.x branch (commit aa4f570):
Bleeding-edge PAReview script crashed in PHPSniffer. Online version came up clean.
Manual Review
(*) I can't get any lists to show up on admin/config/mailman_simple/show after I add them. I can't adequately test this as a result, and it looks like this is
XSS vulnerable, as $list->list_name and $list->description are unfiltered user input. These need to be plained for output. See See https://www.drupal.org/node/28984
In mailman_simple_schema(), you should have a description for the table and each column. You can also add foreign key definitions (useded by code, but useful for documentation purposes).
Single quoted strings are, in general, preferred. See https://www.drupal.org/coding-standards#quotes
Why do you have two $items['mailing_lists'] in your hook_menu? I think as a result, the 'subscribe lists' permissions ends up being unused?
You have some db_select() in the drush commands that are static queries, and can be converted to db_query(). Also elsewhere in the module.
The drush command should probably check that sync_members command actually exists and error if it doesn't.
In mailman_simple_subscribe_form, is 20 characters really long enough for an email address?
Why doesn't this use the registered email account for the user if they are logged in?
(+) mailman_simple_subscribe_form() needs validation on the email element. See #element_validate and valid_email_address().
(+) mailman_simple_form() also needs validation on the email elements.
(+) mailman_simple_get_lists() is defined in the menu callbacks file, but it is used main module. And to get around this you require the callbacks file?
(+) The forms are in a separate include, but the include is not specified in the menu paths.
mailman_simple_get_lists() gets called a lot. Static caching may help (but I dind't trace out exactly how mahy times it wouldbe called during a page request). See https://api.drupal.org/api/drupal/includes!bootstrap.inc/function/drupal...
(+) Shouldn't mailman_simple_subscribe_form_submit() use the langauge for the current session and not the default language for the site?
(+) In mailman_simple_subscribe_form_submit(), t() will sanitize paramters via format_string(). Explicit filter_xss() are not needed and may lead to double escaping, and filter_xss() is only needed when
you expect the values to have HTML in them that you need to have displayed as HTML. See https://www.drupal.org/node/28984
In mailman_simple_subscribe_form_validate(), can't you just make that form element required, which will eliminate the validation you have?
When you execute db_insert() it should return the id already?
Your hook_mail usage is a little wrong. You normally wouldn't use the $key like that, rather pass in message parts via the $params parameter.
Maybe your add list form should #redirect to the view lists page? That sequence was a little confusing.
mailman_simple_show_lists() is a page callback. You should really just return the render array for the table, and not explicitly call theme().
(+) In mailman_simple_subscribe_form(), I would breakout the title and description into different parts in the checkboxes, #title and #description. See comment above about filter_xss().
The starred items (*) are fairly big issues and warrant going back to Needs Work. Items marked with a plus sign (+) are important and should be addressed before a stable project release. The rest of the comments in the code walkthrough are recommendations.
If added, please don't remove the security tag, we keep that for statistics and to show examples of security problems.
Comment #17
spficklin CreditAttribution: spficklin commentedThanks mpdonadio for the great review. I learned some good stuff from that. I addressed the security issue and other suggested issues. Below is a description of changes and in some cases questions I have:
Whoops, sorry about that. It's the admin/config/mailman_simple/show page now works. And I fixed the XSS vulnerability there.
Done.
Switched all to single quotes where appropriate.
Good question. One of those shouldn't have been there. It has been fixed.
I was confused by this suggestion. I thought we should be using these new db_select/insert/update/delete functions as much as possible. Is the recommendation only to use them for dynamic queries?
Done
Probably not. That same form is also used in the block which is intended to appear in the sidebar, so the size was set to 20 to help it fit better in a block. It's probably not the best way to solve that problem.
Very good point. It should. I have fixed it to do so when the user is logged in. For anonymous users it still shows the text field for adding an email address.
Done.
Done
I removed the global file require and moved mailman_simple_get_lists() into the .module file.
The callback include file is no longer globally included, but now the menu items have the 'file' element.
The function could be called twice if the site has the block enabled at the same time the user is visiting the 'mailing_lists' page. But otherwise, I've fixed the code so it only get's called once.
I'm not sure what you mean... I did change the code a bit to check which button was selected. Previously it was trying to translate the button title.
Fixed... removed filter_xss inside of the t() call.
Oh, I should have used the 'checkboxes' form type rather than individual an individual 'checkbox' field for each mailing list. I have switched this code. The field is now required.
Yes, it does. Thanks for catching. I fixed the code to remove the extra query.
Fixed. Thanks for pointing out.
I think because the page showing the lists was broken this didn't work correctly, but it should have redirected as suggested. It does so now.
Fixed.
Yes, good suggestion. Although, I changed this to a 'checkboxes' type.
Thanks again for the review!
Comment #18
mpdonadioRe, the queries. Use db_query() for simple SELECT queries that are static. Use db_select() for SELECT queries for ones where the conditions and/or fields can change (not talking about parameters here). See https://www.drupal.org/node/310072 and https://www.drupal.org/node/310075. It isn't a rule to use one over the other, but db_query() is faster in general.
Re, mailman_simple_subscribe_form_submit() and the language. The default language for the site may not be the one that that the user is using. Read the second paragraph on https://api.drupal.org/api/drupal/includes!mail.inc/function/drupal_mail/7 I think user_preferred_language() is the better option here, but this may be picking nits. To be honest, I am not sure if Mailman will use the subscribe email's language in any real way.
Comment #19
klausiI think this should go directly into a 7.x-1.x branch of one of the existing mailman modules that seem to be abandoned. Module duplication and fragmentation is a huge problem on drupal.org and we prefer collaboration over competition. Creating yet another mailman project namespace will just confuse users. Please open an issue in the mailman issue queue to discuss what you need. You should also get in contact with the maintainer(s) to offer your help to move the project forward. If you cannot reach the maintainer(s) please follow the abandoned project process.
If that fails for whatever reason please get back to us and set this back to "needs review".
Once your code is renamed and pushed into one of the existing projects we can continue here with the project application to grant you the git vetted user role, just set the issue back to "needs review" once you are ready. Thanks for your understanding.
Comment #20
spficklin CreditAttribution: spficklin commentedHi Klausi,
I am happy to proceed as you suggest. I understand the desire to reduce duplication and fragmentation of modules. No worries...
However, I have other projects in my sandbox that I would like to promote to full project status which I cannot promote despite having passed through the entire review process. The promotion of those projects is held up because of the duplication/fragmentation issue of this particular project. At this point, I'm at the mercy of the other mailman module maintainers and perhaps months more time resolving the issue... or I must submit a different module for review and start all over again. If it appears that I have properly satisfied all of the review requirements that developers must meet (as demonstrated by the coding of this module) could you grant my account the git vetted user role so those other projects are not held up? Then I can work on the duplication/fragmentation issue of this mailman_simple project separately (as you suggest) but without holding up my other projects.
Thanks for the consideration on this...
Comment #21
klausiAs indicated in https://www.drupal.org/node/251466 taking over an abandoned project should only take 2 weeks, after that time you escalate the project ownership issue to the Drupal.org webmasters if you cannot reach the maintainers.
Can you hold on for another 2-3 weeks? You can also open another project application for your other projects and close this one, but that will most likely also take a couple of weeks.
Comment #22
spficklin CreditAttribution: spficklin commentedI have submitted an issue on the Mailman Mailing List Management Wrapper project, (https://www.drupal.org/node/36863), for transfer of ownership or to include me as a maintainer so I can merge in this project... will respond back as things unfold. That project supports management of Mailman using the command-line, so in that regard it has the closest overlap with this project and I think therefore the best fit.
Comment #23
spficklin CreditAttribution: spficklin commentedOkay, I am now the maintainer of the "mlist" project (https://www.drupal.org/node/2315105). The project maintainer could not be reached within the two week time period and ownership of the project was transferred to me. I have done the following:
1) Created a 7.x-1.x branch.
2) Imported the code from my sandbox to maintain the commit history.
3) Renamed the code from 'mailman_simple' to 'mlist'.
4) Checked the code on pareview.sh again just to double check all is good.
5) Updated the project description on the project page.
6) Created a 7.x-2.x-dev release node.
Although, I am unable to delete the old 'master branch' as it appears to be tied to a release node. Because I am not the owner of the release node I'm not able to change the branch from master (as per these instructions https://www.drupal.org/node/1127732).
But aside from that I believe things are ready to continue with the review process.
Comment #24
laceysanderson CreditAttribution: laceysanderson commentedReviews of the 7.x-1.x branch (commit df87a66):
Automated review came back clean except for the master branch issue mentioned in comment #23.
Manual Review
Individual user account
Yes: Follows the guidelines for individual user accounts.
No duplication
Yes: Does not cause module duplication and fragmentation. I think this was adequately addressed through take-over of the mlist project.
Master Branch
No: Due to a permissions problem since it's tied to an old release node. Maybe someone with more power in the drupal community can delete the old release node?
Licensing
Yes: Follows the licensing requirements
3rd party code
Yes: Follows the guidelines for 3rd party code.
README.txt/README.md
Yes: Follows the guidelines for in-project documentation and the README Template.
Code long/complex enough for review
Yes: Follows the guidelines for project length and complexity.
Secure code
Yes. I didn't see any security issues & it appears the issue mentioned above was fixed (mlist.callbacks.inc:502-503) :)
Coding style & Drupal API usage
(+) I am not sure if hardcoding /tmp is a good idea. file_directory_temp() is probably safer here, and will provide Windows support.
Your mailman sync drush command should output something if is run when no mailing lists are yet registered with the module (ie: if the mailing_lists table is empty).
(+) Add a configuration link to the module page to make for easy finding of your administration pages. See https://www.drupal.org/node/542202. I would link to the view mailing lists page and add an action link (using hook_menu with type MENU_LOCAL_ACTION) to add the "Add Mailing list link to this page.
Not seeing anything to prevent RTBC with this. Verified that code was committed in #2315105: Offering to maintain Mailman Mailing List Management Wrapper. This review was done on http://git.drupal.org/project/mlist.git even though I notice your link in the issue still points to your sandbox. The repo link should be adjusted before final review.
Comment #25
spficklin CreditAttribution: spficklin commentedComment #26
pkamerakodi CreditAttribution: pkamerakodi commented1) In the below code can be improved from
if (in_array($list->role_name, array_values($user->roles)) or
user_access('manage mailing lists')) {
// Don't add the list more than once.
if (!in_array($list->list_id, $mylists)) {
$mylists[$list->list_id] = array(
'name' => $list->list_name,
'description' => $list->description,
'subscribe' => $list->subscribe_email,
'unsubscribe' => $list->unsubscribe_email,
);
}
}
TO
if ((in_array($list->role_name, array_values($user->roles)) || user_access('manage mailing lists')) && !in_array($list->list_id, $mylists)) {
$mylists[$list->list_id] = array(
'name' => $list->list_name,
'description' => $list->description,
'subscribe' => $list->subscribe_email,
'unsubscribe' => $list->unsubscribe_email,
);
}
2) Minor code improvements in mailman_simple_subscribe_form
a) if (count($lists) > 0) { could be changed to if (count($lists)) {
b) if ($user->uid == 0) could be changed to if (!$user->uid)
3) Minor code improvements in the function mailman_simple_form
// Initialize the default values.
$default_sync = array();
$default_roles = array();
$default_name = '';
$default_desc = '';
$default_sub = '';
$default_usub = '';
if (array_key_exists('values', $form_state)) {
$default_name = array_key_exists('list_name', $form_state['values']) ? $form_state['values']['list_name'] : '';
$default_desc = array_key_exists('description', $form_state['values']) ? $form_state['values']['description'] : '';
$default_sub = array_key_exists('subscribe_email', $form_state['values']) ? $form_state['values']['subscribe_email'] : '';
$default_usub = array_key_exists('unsubscribe_email', $form_state['values']) ? $form_state['values']['unsubscribe_email'] : '';
$default_sync = array_key_exists('sync', $form_state['values']) ? $form_state['values']['sync'] : '';
$default_roles = array_key_exists('default_roles', $form_state['values']) ? $form_state['values']['default_roles'] : '';
}
This piece of code could we better written by using
$default_sync = !empty($form_state['values']['list_name']) ? $form_state['values']['list_name'] : '';
So that we could reduce lot of code here
Could we also please change below code to use ternary operator than if statements
if (!$default_name) {
$default_name = $list->list_name;
}
if (!$default_desc) {
$default_desc = $list->description;
}
if (!$default_sub) {
$default_sub = $list->subscribe_email;
}
if (!$default_usub) {
$default_usub = $list->unsubscribe_email;
}
4) Could you also please simply the drush_mailman_simple_mailman_sync , i mean could you modularize it a bit more into couple functions
Please let me know if you need more info.
Regards,
Prajwal
Comment #27
pkamerakodi CreditAttribution: pkamerakodi commentedComment #28
spficklin CreditAttribution: spficklin commentedThanks laceysanderson for the review!! I've made the following adjustments as you suggested:
Comment #29
spficklin CreditAttribution: spficklin commentedHi pkamerakodi, thanks for taking the time to review the project. I will definitely take a look at your coding suggestions. However, I'm switching the status back to RTBC as the changes you suggest I think are more personal style rather than mistakes in the Drupal coding and security standards.
Comment #30
pkamerakodi CreditAttribution: pkamerakodi commentedHi Sir,
Sure. Sorry if you have mistaken me. Just thought of sharing my thoughts. Would be of a great help from you if you could share your review thoughts on one of my modules "https://www.drupal.org/node/2326909"
Regards,
Prajwal
Comment #31
ram0108 CreditAttribution: ram0108 commentedHI
Thanks for your contribution.
Your module coded in nice mannager. I got following to issues in your module.
1 - Please user db_select() instead of simple mysql select statement. while you used db_select in other module functions.
2 - There is not any need to define array or argument type in function defination.
function mlist_validate_email(array $element, array &$form_state, array $form). However it is not an error.
Thanks!!
Comment #32
klausiFor simple queries db_query() is perfectly fine, see https://www.drupal.org/node/310075
Type hinting for parameters is recommended, so that is also not a problem.
Looks like you have not found any application blocking issues.
Comment #33
ram0108 CreditAttribution: ram0108 commentedHi klausi,
Thanks for quick reply on my comments.
db_query() is always used for the query, where small amount of data need to fetch like value for one column or count etc. how ever it is not a good practise.
In your query i can see you are using "join statement" to join 3 database tables. I dont think that it is simple query.
You must use db_select() instead of db_query().
Also i read artcile link which you posted above, there is nothing like this that it is recommanded to use db_query() for any kind of join query.
About second comments -- "Type hinting for parameters is recommended, so that is also not a problem."
I did not see anywhere in drupal.. however if you are recommending like this then you must use type hinting everywhere in all function of you module files, not in one or two function.
Thanks!!
Comment #34
klausiUsage of db_query() is good practice if the query is static, which seems to be the case here. It is a matter of taste if you want to use db_select() or not here, so not an application blocker.
Type hinting is mostly used in D8 for object oriented code, but it is perfectly fine in D7 as well. There is no rule that all code must be type hinted or not, that is up to the developer to decide.
So those two issues are not application blockers.
Comment #35
mpdonadioI concur with @klausi here.
Ignoring tags and extensions, db_query() vs db_select() boils down to whether the query is static or not (eg, joining or not based on PHP logic), and not the complexity of the query. See https://www.drupal.org/node/310075 For static queries, though, using one over the other isn't a mandatory decision.
Reviews are not meant to hold back release so that they can be perfect. They are sanity checks to make sure developers have a decent idea of what they are doing. Blocking issues are security issues, major API problems, duplication, and a few others. The review admins will sometimes send a module back for one round of polishing, but we don't want to hold back promotion for little things.
Comment #36
klausiThere is still a master branch, make sure to set the correct default branch: https://www.drupal.org/node/1659588 . Then remove the master branch, see also step 6 and 7 in https://www.drupal.org/node/1127732
Review of the 7.x-1.x branch (commit 22d1b70):
This automated report was generated with PAReview.sh, your friendly project application review script. You can also use the online version to check your project. You have to get a review bonus to get a review from me.
manual review:
But otherwise looks good to me, so ...
Thanks for your contribution, spficklin!
I updated your account so you can promote this to a full project and also create new projects as either a sandbox or a "full" project.
Here are some recommended readings to help with excellent maintainership:
You can find lots more contributors chatting on IRC in #drupal-contribute. So, come hang out and stay involved!
Thanks, also, for your patience with the review process. Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.
Thanks to the dedicated reviewer(s) as well.
Comment #37
spficklin CreditAttribution: spficklin commentedThanks Klausi! Much appreciated!
I have, made the fixes to the code that your raised from your manual review. In regards to the drupal_mail function that was a mistake and that first argument should be 'mlist' (the module name). Thanks for noticing.
I am not able to remove the master branch. I tried when I first took over the mlist module but I get this message:
The master branch appears to be tied to a very old release node: https://www.drupal.org/node/95847. Because I am not the owner of the release node I'm not able to change the branch from master (as per these instructions https://www.drupal.org/node/1127732). Is there a way to grant me ownership of that node so I can fix it?