diff --git a/includes/simplenews.admin.inc b/includes/simplenews.admin.inc index 9fce347..dcf38f8 100644 --- a/includes/simplenews.admin.inc +++ b/includes/simplenews.admin.inc @@ -284,8 +284,13 @@ function simplenews_issue_send($nids) { continue; } - simplenews_update_sent_status($node); - simplenews_add_node_to_spool($node); + $status = simplenews_add_node_to_spool($node); + if ($status == SIMPLENEWS_STATUS_SEND_READY) { + drupal_set_message(t('Newsletter %title sent.', array('%title' => $node->title))); + } + else { + drupal_set_message(t('Newsletter %title pending.', array('%title' => $node->title))); + } } } diff --git a/includes/simplenews.api.php b/includes/simplenews.api.php index 5afc107..7fde931 100644 --- a/includes/simplenews.api.php +++ b/includes/simplenews.api.php @@ -67,3 +67,29 @@ function hook_simplenews_subscriber_insert($subscriber) { function hook_simplenews_subscriber_delete($subscriber) { } + +/** + * Invoked if a user is subscribed to a newsletter. + * + * @param $subscriber + * The subscriber object including all subscriptions of this user. + * + * @param $subscription + * The subscription object for this specific subscribe action. + */ +function hook_simplenews_subscribe_user($subscriber, $subscription) { + +} + +/** + * Invoked if a user is unsubscribed from a newsletter. + * + * @param $subscriber + * The subscriber object including all subscriptions of this user. + * + * @param $subscription + * The subscription object for this specific unsubscribe action. + */ +function hook_simplenews_unsubscribe_user($subscriber, $subscription) { + +} diff --git a/includes/simplenews.mail.inc b/includes/simplenews.mail.inc index 8e89ac3..b16110c 100644 --- a/includes/simplenews.mail.inc +++ b/includes/simplenews.mail.inc @@ -4,54 +4,52 @@ * @file * Simplenews email send and spool handling * - * @ingroup simplenews + * @ingroup mail */ - /** - * Send newsletter node to subscribers. +/** + * Add the newsletter node to the mail spool. * - * @param mixed $node - * The newsletter node to be sent. If an integer, the node nid; if an object, - * the node object. + * Depending on the configuration, the node will either be sent immediatly + * afterwards or during cron runs. + * + * @param $node + * The newsletter node to be sent. */ function simplenews_add_node_to_spool($node) { - if (is_numeric($node)) { - $node = node_load($node); - } + // To send the newsletter, the node id and target email addresses + // are stored in the spool. + // Only subscribed recipients are stored in the spool (status = 1). + $select = db_select('simplenews_subscriber', 's'); + $select->innerJoin('simplenews_subscription', 't', 's.snid = t.snid'); + $select->addField('s', 'mail'); + $select->addField('s', 'snid'); + $select->addField('t', 'tid'); + $select->addExpression($node->nid, 'nid'); + $select->addExpression(SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED, 'status'); + $select->addExpression(REQUEST_TIME, 'timestamp'); + $select->condition('t.tid', $node->simplenews->tid); + $select->condition('t.status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED); + $select->condition('s.activated', SIMPLENEWS_SUBSCRIPTION_ACTIVE); - if (is_object($node)) { - // To send the newsletter, the node id and target email addresses - // are stored in the spool. - // Only subscribed recipients are stored in the spool (status = 1). - $select = db_select('simplenews_subscriber', 's'); - $select->innerJoin('simplenews_subscription', 't', 's.snid = t.snid'); - $select->addField('s', 'mail'); - $select->addField('s', 'snid'); - $select->addField('t', 'tid'); - $select->addExpression($node->nid, 'nid'); - $select->addExpression(SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED, 'status'); - $select->addExpression(REQUEST_TIME, 'timestamp'); - $select->condition('t.tid', $node->simplenews->tid); - $select->condition('t.status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED); - $select->condition('s.activated', SIMPLENEWS_SUBSCRIPTION_ACTIVE); - - $query = db_insert('simplenews_mail_spool') - ->from($select) - ->execute(); - - // When cron is not used the newsletter is send immediately to the emails - // in the spool. When cron is used newsletters are send to addresses in the - // spool during the next (and following) cron run. - if (variable_get('simplenews_use_cron', TRUE) == FALSE) { - simplenews_mail_spool(); - drupal_set_message(t('Newsletter sent.')); - simplenews_clear_spool(); - simplenews_send_status_update(); - } - else { - drupal_set_message(t('Newsletter pending.')); - } + db_insert('simplenews_mail_spool') + ->from($select) + ->execute(); + // Update simplenews newsletter status to send pending. + simplenews_update_sent_status($node); + + // When cron is not used the newsletter is send immediately to the emails + // in the spool. When cron is used newsletters are send to addresses in the + // spool during the next (and following) cron run. + if (variable_get('simplenews_use_cron', TRUE) == FALSE) { + simplenews_mail_spool(); + simplenews_clear_spool(); + simplenews_send_status_update(); + return SIMPLENEWS_STATUS_SEND_READY; + } + else { + return SIMPLENEWS_STATUS_SEND_PENDING; } } diff --git a/simplenews.module b/simplenews.module index f233921..250d687 100644 --- a/simplenews.module +++ b/simplenews.module @@ -484,7 +484,6 @@ function simplenews_node_update($node) { // Check if the newsletter is set to send on publish and needs to be send. if ($node->simplenews->status == SIMPLENEWS_STATUS_SEND_PUBLISH && $node->status == NODE_PUBLISHED) { module_load_include('inc', 'simplenews', 'includes/simplenews.mail'); - simplenews_update_sent_status($node); simplenews_add_node_to_spool($node); } else { @@ -1371,8 +1370,9 @@ function simplenews_subscribe_user($mail, $tid, $confirm = TRUE, $source = 'unkn $subscription->source = $source; simplenews_subscription_save($subscription); $subscriber->tids[$tid] = $tid; + + module_invoke_all('simplenews_subscribe_user', $subscriber, $subscription); } - module_invoke_all('simplenews_subscribe_user', $subscriber); return TRUE; } @@ -1430,8 +1430,9 @@ function simplenews_unsubscribe_user($mail, $tid, $confirm = TRUE, $source = 'un $subscription->source = $source; simplenews_subscription_save($subscription); $subscriber->tids[$tid] = $tid; + + module_invoke_all('simplenews_unsubscribe_user', $subscriber, $subscription); } - module_invoke_all('simplenews_unsubscribe_user', $subscriber); return TRUE; } @@ -2982,8 +2983,13 @@ function simplenews_node_tab_send_form_submit($form, &$form_state) { // Send newsletter to all subscribers or send test newsletter module_load_include('inc', 'simplenews', 'includes/simplenews.mail'); if ($values['simplenews']['send'] == SIMPLENEWS_COMMAND_SEND_NOW) { - simplenews_update_sent_status($node); - simplenews_add_node_to_spool($node); + $status = simplenews_add_node_to_spool($node); + if ($status == SIMPLENEWS_STATUS_SEND_READY) { + drupal_set_message(t('Newsletter %title sent.', array('%title' => $node->title))); + } + else { + drupal_set_message(t('Newsletter %title pending.', array('%title' => $node->title))); + } } elseif ($values['simplenews']['send'] == SIMPLENEWS_COMMAND_SEND_TEST) { simplenews_send_test($node, $form_state['test_addresses']); diff --git a/simplenews_rules/simplenews_rules.info b/simplenews_rules/simplenews_rules.info new file mode 100644 index 0000000..b7a3387 --- /dev/null +++ b/simplenews_rules/simplenews_rules.info @@ -0,0 +1,6 @@ +name = Simplenews rules +description = Provides integration with Rules module for Simplenews. +dependencies[] = simplenews +dependencies[] = rules +package = Mail +core = 7.x diff --git a/simplenews_rules/simplenews_rules.module b/simplenews_rules/simplenews_rules.module new file mode 100755 index 0000000..96cf792 --- /dev/null +++ b/simplenews_rules/simplenews_rules.module @@ -0,0 +1,44 @@ + t('Default'), + SIMPLENEWS_RULES_CONFIRMATION_YES => t('Yes'), + SIMPLENEWS_RULES_CONFIRMATION_NO => t('No'), + ); +} + +/** + * Implements hook_simplenews_unsubscribe_user(). + */ +function simplenews_rules_simplenews_unsubscribe_user($subscriber, $subscription) { + $args = array( + 'mail' => $subscriber->mail, + 'tid' => $subscription->tid, + ); + rules_invoke_event_by_args('simplenews_rules_event_unsubscribe', $args); +} + +/** + * Implements hook_simplenews_unsubscribe_user(). + */ +function simplenews_rules_simplenews_subscribe_user($subscriber, $subscription) { + $args = array( + 'mail' => $subscriber->mail, + 'tid' => $subscription->tid, + ); + rules_invoke_event_by_args('simplenews_rules_event_subscribe', $args); +} \ No newline at end of file diff --git a/simplenews_rules/simplenews_rules.rules.inc b/simplenews_rules/simplenews_rules.rules.inc new file mode 100755 index 0000000..8838e6e --- /dev/null +++ b/simplenews_rules/simplenews_rules.rules.inc @@ -0,0 +1,218 @@ + array( + 'label' => t('Send newsletter'), + 'group' => t('Simplenews'), + 'parameter' => array( + 'node' => array( + 'type' => 'node', + 'label' => t('The newsletter node to be sent.'), + 'description' => t('The newsletter node that should be sent.'), + ) + ) + ), + 'simplenews_rules_action_subscribe' => array( + 'label' => t('Subscribe an e-mail adress to a newsletter'), + 'group' => t('Simplenews'), + 'named parameter' => TRUE, + 'parameter' => array( + 'mail' => array( + 'type' => 'text', + 'label' => t('E-mail'), + 'description' => t('The e-mail address that should be subscribed.'), + ), + 'tid' => array( + 'type' => 'integer', + 'label' => t('Simplenews category'), + 'descrption' => t('For which newsletter category the subscription should happen.'), + 'options list' => 'simplenews_category_list', + ), + 'confirmation' => array( + 'type' => 'integer', + 'label' => t('Confirmation required'), + 'description' => t('Select if a confirmation is required. Default uses the default setting from the chosen newsletter category.'), + 'options list' => 'simplenews_rules_confirmation_list', + 'default value' => SIMPLENEWS_RULES_CONFIRMATION_DEFAULT, + ), + 'source' => array( + 'type' => 'string', + 'label' => t('Source'), + 'description' => t('A string to identify the source of this subscription'), + 'optional' => TRUE, + ), + 'source' => array( + 'type' => 'text', + 'label' => t('Source'), + 'description' => t('A string to identify the source of this subscription'), + 'optional' => TRUE, + 'default value' => 'rules', + ), + 'language' => array( + 'type' => 'token', + 'label' => t('Language'), + 'description' => t('If specified, the language to use for the subscription. Defaults to the default language.'), + 'options list' => 'entity_metadata_language_list', + 'optional' => TRUE, + 'default value' => LANGUAGE_NONE, + ), + ), + ), + 'simplenews_rules_action_unsubscribe' => array( + 'label' => t('Unsubscribe an e-mail adress from a newsletter'), + 'group' => t('Simplenews'), 'named parameter' => TRUE, + 'parameter' => array( + 'mail' => array( + 'type' => 'text', + 'label' => t('E-mail'), + 'description' => t('The e-mail address that should be unsubscribed.'), + ), + 'tid' => array( + 'type' => 'integer', + 'label' => t('Simplenews category'), + 'descrption' => t('For which newsletter category the unsubscription should happen.'), + 'options list' => 'simplenews_category_list', + ), + 'confirmation' => array( + 'type' => 'integer', + 'label' => t('Confirmation required'), + 'description' => t('Select if a confirmation is required. Default uses the default setting from the chosen newsletter category.'), + 'options list' => 'simplenews_rules_confirmation_list', + 'default value' => SIMPLENEWS_RULES_CONFIRMATION_DEFAULT, + ), + 'source' => array( + 'type' => 'text', + 'label' => t('Source'), + 'description' => t('A string to identify the source of this subscription'), + 'optional' => TRUE, + 'default value' => 'rules', + ), + 'language' => array( + 'type' => 'token', + 'label' => t('Language'), + 'description' => t('If specified, the language to use for the subscription. Defaults to the default language.'), + 'options list' => 'entity_metadata_language_list', + 'optional' => TRUE, + 'default value' => LANGUAGE_NONE, + ), + ), + ), + ); +} + +/** + * Implements hook_event_info(). + */ +function simplenews_rules_rules_event_info() { + return array( + 'simplenews_rules_event_subscribe' => array( + 'label' => t('A user has been subscribed'), + 'group' => t('Simplenews'), + 'variables' => array( + 'mail' => array( + 'type' => 'text', + 'label' => t('E-Mail'), + 'description' => t('The e-mail address that has been subscribed.'), + ), + 'tid' => array( + 'type' => 'integer', + 'label' => t('Simplenews category'), + 'descrption' => t('The newsletter category of the subscription.'), + 'options list' => 'simplenews_category_list', + ), + ), + ), + 'simplenews_rules_event_unsubscribe' => array( + 'label' => t('A user has been unsubscribed'), + 'group' => t('Simplenews'), + 'variables' => array( + 'mail' => array( + 'type' => 'text', + 'label' => t('E-mail'), + 'description' => t('The e-mail address that has been subscribed.'), + ), + 'tid' => array( + 'type' => 'integer', + 'label' => t('Simplenews category'), + 'descrption' => t('The newsletter category of the subscription.'), + 'options list' => 'simplenews_category_list', + ), + ), + ), + ); +} + +/** + * Action implementation, send a newsletter node. + */ +function simplenews_rules_action_send($node) { + $newsletter = simplenews_newsletter_load($node->nid); + if ($newsletter && ($newsletter->status != SIMPLENEWS_STATUS_SEND_PENDING || $newsletter->status != SIMPLENEWS_STATUS_SEND_PENDING)) { + module_load_include('inc', 'simplenews', 'includes/simplenews.mail'); + simplenews_add_node_to_spool($node); + } +} + +/** + * Action Implementation: Subscribe an e-mail adress to a Simplenews newsletter. + */ +function simplenews_rules_action_subscribe($args, $settings) { + if ($args['language'] == LANGUAGE_NONE) { + $args['language'] = NULL; + } + + $confirmation = simplenews_rules_map_confirmation($args); + + // Pass the call forward. + simplenews_subscribe_user($args['mail'], $args['tid'], $confirmation, $args['source'], $args['language']); +} + +/** + * Action Implementation: Unsubscribe an e-mail adress to a Simplenews newsletter. + */ +function simplenews_rules_action_unsubscribe($args, $settings) { + if ($args['language'] == LANGUAGE_NONE) { + $args['language'] = NULL; + } + + $confirmation = simplenews_rules_map_confirmation($args); + + // Pass the call forward. + simplenews_unsubscribe_user($args['mail'], $args['tid'], $confirmation, $args['source'], $args['language']); +} + + +/** + * Map args to the confrmation argument for subscribing/unsubscribing. + */ +function simplenews_rules_map_confirmation($args) { + switch ($args['confirmation']) { + case SIMPLENEWS_RULES_CONFIRMATION_YES: + $confirmation = TRUE; + break; + case SIMPLENEWS_RULES_CONFIRMATION_NO: + $confirmation = FALSE; + break; + case SIMPLENEWS_RULES_CONFIRMATION_DEFAULT: + $account = _simplenews_user_load($args['mail']); + $confirmation = simplenews_require_double_opt_in($args['tid'], $account); + break; + } + return $confirmation; +} + +/** + * @} + */ diff --git a/tests/simplenews.test b/tests/simplenews.test index 6fe7445..92aede0 100644 --- a/tests/simplenews.test +++ b/tests/simplenews.test @@ -1215,7 +1215,7 @@ class SimplenewsSendTestCase extends SimplenewsTestCase { ); $this->drupalPost('admin/content/simplenews', $edit, t('Update')); - $this->assertText(t('Newsletter sent')); + $this->assertText(t('Newsletter @title sent', array('@title' => $first->title))); $this->assertText(t('Newsletter @title is unpublished and will be sent on publish', array('@title' => $unpublished->title))); // Verify states.