CVS edit link for ositoblanco

For a community platform I developed the following digest module:

The digest module provides API functionality to send status or digest mails
to users once a day to inform them about new activities (like new unread private messages or new unconfirmed relationship requests).

This module is an API, therefore it does not provide new functionality to your site, unless you use other modules which take use of the digest functions.

Two modules are contributed to demonstrate the use of the Digest module:
contributed_modules/user_relationships_digest and
contributed_modules/privatemsg_digest.

Comments

osopolar’s picture

Status: Postponed (maintainer needs more info) » Needs review
StatusFileSize
new33.89 KB
avpaderno’s picture

Issue tags: +Module review

Hello, and thanks for applying for a CVS account. I am adding the review tags, and some volunteers will review the code, pointing out what it needs to be changed.

berdir’s picture

I've just looked at the privatemsg related sub-module...

- Note that the database schema has changed in privatemsg 6.x-2.x. This is not a problem in your code, just an information :)
- You're doing a pretty huge query with a ton of left joins there. Given that the pm_ tables could contain a very large number of entries, this might be quite slow. But I'm not sure if there is a better way.
- You should use the db_placeholders (http://api.drupal.org/api/function/db_placeholders/6) function to insert the role ids...

avpaderno’s picture

Status: Needs review » Needs work

I am changing the status as per previous comment; db_query()-placeholders should be used instead of injecting a value into the query, especially if the value is not static.

osopolar’s picture

StatusFileSize
new33.97 KB

Actually the submodules should go into the core of the corresponding modules, due the digest is an api and should not take care about database change - as recently in privatemsg 6.x-2.x. Anyway the code of the submodules is very important.

If somebody sees how to cut down the large sql queries, just leave a node. The only thing (actually I did before in a previous version) is to use an inner select instead of the users_roles join:

...
AND pmi.uid IN (SELECT uid FROM {users_roles} WHERE rid IN (%s))
...

One idea came into my mind to improve performance (not yet in the code):

As far as we are only interested to inform the user about new private messages (or new relationship requests) we can modify the query to only take in account the new messages which were send after the last digest run and before the current one (see INNER JOIN {pm_index}). As far as I know this should be SQL standards-compliant.

$results = db_queryd("SELECT pmi.uid uid, count(distinct pmi.mid) count_messages, u.mail mail, u.name name, u.language language
  FROM {pm_message} pm
  INNER JOIN {pm_index} pmi ON (pm.mid = pmi.mid AND pmi.is_new = 1 AND pm.timestamp > %d AND pm.timestamp < %d)
  INNER JOIN {users} u ON pmi.uid = u.uid
  LEFT JOIN {users_roles} ur ON pmi.uid = ur.uid
  LEFT JOIN {digest_user_settings} tds ON pmi.uid = tds.uid
  LEFT JOIN {digest} td ON pmi.uid = td.uid
  WHERE ((tds.notify = 1 AND tds.type = 'privatemsg') %s)
  AND (ur.rid IN (" . db_placeholders($allowed_roles, 'int') . ") OR %d)
  AND (td.notified IS NULL
      OR (pm.timestamp > td.notified AND (td.notified <= %d)))
  GROUP BY pmi.uid",
  array_merge((array) digest_get_start_timestamp('last'), (array) digest_get_start_timestamp('current'),
              (array) $user_notity_default_query, $allowed_roles, (array) $allowed_roles_authenticated_user,
  )
);

Will there be any benefit from using _privatemsg_assemble_query?

@Bendir Thanks for reviewing the privatemsg related sub-module. If you would like to have this feature in privatemsg please have a look at the other code ... actually the tough part of the module are the sql queries in the submodule

osopolar’s picture

Status: Needs work » Needs review
avpaderno’s picture

Status: Needs review » Needs work
  • This is a partial review.
  • The points reported in this review are not in order of importance / relevance.
  • Most of the times I report the code that present an issue. In such cases, the same error can be present in other parts of the code; the fact I don't report the same issue more than once doesn't mean the same issue is not present in different places.
  • Not all the reported points are application blockers; some of the points I report are simple suggestions to who applies for a CVS account. For a list of what is considered a blocker for the application approval, see CVS applications review, what to expect. Keep in mind the list is still under construction, and can be changed to adapt it to what has been found out during code review, or to make the list clearer to who applies for a CVS account.
  1. The version line needs to be removed from the .info file.
  2. function digest_uninstall() {
      db_query("DELETE FROM {variable} WHERE name LIKE 'digest%%'");
      drupal_uninstall_schema('digest');
    }
    

    Deleting Drupal variables using a query that matches any Drupal variable with a name that starts with the module name would remove also the Drupal variables of other modules.

  3.     if (variable_get('digest_verbosity', 1)) {
          watchdog('digest', 'There where no digest mails to be send.', array(), WATCHDOG_DEBUG);
        }
    
    

    It should be there were no digest mails.

  4.     if (variable_get('digest_verbosity', 1)) {
          watchdog('digest', 'Digest mail sent to !uid (!username, !mail).', array('!uid' => $uid, '!username' => $digest_user_info['#user']['name'], '!mail' => $digest_user_info['#user']['mail']), WATCHDOG_DEBUG);
        }
    
    

    The username could contain characters that have particular meaning for HTML.

  5.   $options = array(
        0 => 0,
        1 => 1,
        2 => 2,
        3 => 3,
        4 => 4,
        5 => 5,
        6 => 6,
        7 => 7,
        8 => 8,
        9 => 9,
        10 => 10,
        11 => 11,
        12 => 12,
        13 => 13,
        14 => 14,
        15 => 15,
        16 => 16,
        17 => 17,
        18 => 18,
        19 => 19,
        20 => 20,
        21 => 21,
        22 => 22,
        23 => 23,
      );
    
      $form['digest_cron']['digest_notify_start_time'] = array(
        '#type' => 'select',
        '#title' => t('Start time'),
        '#description' => t('At that time the cron job starts a new digest run. The time the digest mail actually will be send depends on the amount of digest messages to be send and how many of them could be send per cron run. This could result in various cron runs for one digest. In this case notifications for activities which are taking place after the digest has started will be delivered by the next digest run (at the next day) &emdash; not by the next cron run at the same day.'),
        '#options' => $options,
        '#default_value' => variable_get('digest_notify_start_time', 18),
      );
    
    

    The array $options should simply be array(0, 1, 2, 3, 4, /*... */), or range(0, 23).

  6.   $form['digest_mail'] = array(
        '#type' => 'fieldset',
        '#title' => t('Digest mail'),
        '#collapsible' => FALSE,
        '#collapsed' => FALSE,
      );
    
    

    By default, a fieldset is not collapsible, and not collapsed; the default values should not be declared.

  7. function _digest_notify_default_subject() {
      $default_subject = variable_get('site_name', '')? '[' . variable_get('site_name', '') . '] - ' : '';
      $default_subject .= 'Notification';
      
      return $default_subject;
    }
    
    

    Strings used in the user interface should be translated.

osopolar’s picture

Status: Needs work » Needs review
StatusFileSize
new29.79 KB

@kiamlaluno: Thank you, for reviewing my code.

Comment to (2: "DELETE FROM {variable} WHERE name LIKE 'digest%%'") ... removed. But now each implementing module is responsible to delete variables like digest_roles_permissions_{modulename} and digest_message_part_{modulename}. Is this OK? or should I rename them to {modulname}_digest_roles_permissions and {modulename}_digest_message_part?

I've attached the updated version of digest module.

avpaderno’s picture

If the module name is digest.module, then every Drupal variable name should be prefixed by digest_.

osopolar’s picture

StatusFileSize
new29.77 KB

The variables depending on the implementing module (eg. privatemsg_digest) like digest_roles_permissions_privatemsg and digest_message_part_privatemsg are somehow special. They are set by the digest module settings, but they will get deleted by the uninstall hook of the implementing module. This is the only way I can see to delete them.

For example:

function permissions_digest_uninstall() {  
  variable_del('digest_roles_permissions_privatemsg');
  variable_del('digest_message_part_privatemsg');
}

The new version fixes a copy paste error in the contributed modules - the uninstall hook called accidentally drupal_uninstall_schema('digest');

drupalshrek’s picture

Looks good to me.

A couple of small things:
1) README.txt I think doesn't need $Id$

2) LICENCE.txt is not needed as CVS will add this automatically

zzolo’s picture

Component: Miscellaneous » miscellaneous
Status: Needs review » Postponed

Hi. Please read all the following and the links provided as this is very important information about your CVS Application:

Drupal.org has moved from CVS to Git! This is a very significant change for the Drupal community and for your application. Please read the following documentation on how this affects and benefits you and the application process:
Migrating from CVS Applications to (Git) Full Project Applications

  • The status of this application will be put to "postponed" and by following the instructions in the above link, you will be able to reopen it.
  • Or if your application has been "needs work" for more than 5 weeks, your application will be marked as "closed (won't fix)". You can still reopen it, by reading the instructions above.
avpaderno’s picture

Issue summary: View changes
Status: Postponed » Closed (won't fix)

As per previous comment, I am setting this issue to won't fix.

Since new users can now create full projects, applications have a different purpose and they are handled on a different issue queue. See Apply for permission to opt into security advisory coverage for more information.

avpaderno’s picture

Component: miscellaneous » new project application