From 4deaf092124523f7db55ebcef511da393de8b4bf Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sun, 16 Sep 2007 00:57:31 +0000 Subject: [PATCH] elofgren: Track whether mail() returns TRUE or FALSE when a Newsletter is sent and record the result in a new Newsletter_SentRecipient table. Add a 'Sent Status Report' tab to Newsletters that shows the following 4 reports: * Sending to the Following Recipients Failed * Sending to the Following Recipients Bounced (@TODO: Make bounces actually show up here) * The Newsletter has Never Been Sent to Following Subscribers * Sending to the Following Recipients was Successful More info: http://support.silverstripe.com/gsoc/wiki/GSoc07UsabilityElijah (merged from branches/gsoc) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@41995 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- code/Newsletter/Newsletter.php | 72 ++++++++++++++++- code/Newsletter/NewsletterEmailProcess.php | 31 ++++++-- code/NewsletterAdmin.php | 13 ++- javascript/NewsletterAdmin_right.js | 12 +++ templates/Newsletter_SentStatusReport.ss | 93 ++++++++++++++++++++++ 5 files changed, 213 insertions(+), 8 deletions(-) create mode 100644 templates/Newsletter_SentStatusReport.ss diff --git a/code/Newsletter/Newsletter.php b/code/Newsletter/Newsletter.php index 2c8bd2ee..bd97ced8 100755 --- a/code/Newsletter/Newsletter.php +++ b/code/Newsletter/Newsletter.php @@ -11,12 +11,15 @@ class Newsletter extends DataObject { require_once("forms/Form.php"); $group = DataObject::get_by_id("Group", $this->Parent()->GroupID); - + $sent_status_report = $this->renderWith("Newsletter_SentStatusReport"); $ret = new FieldSet( new TabSet("Root", $mailTab = new Tab("Newsletter", new TextField("Subject", "Subject", $this->Subject), new HtmlEditorField("Content", "Content") + ), + $sentToTab = new Tab("Sent Status Report", + new LiteralField("Sent Status Report", $sent_status_report) ) ) ); @@ -28,7 +31,58 @@ class Newsletter extends DataObject { return $ret; } + + /** + * Returns a DataObject listing the recipients for the given status for this newsletter + * + * @param string $result 3 possible values: "Sent", (mail() returned TRUE), "Failed" (mail() returned FALSE), or "Bounced" ({@see $email_bouncehandler}). + */ + function SentRecipients($result) { + $SQL_result = Convert::raw2sql($result); + return DataObject::get("Newsletter_SentRecipient",array("ParentID='".$this->ID."'", "Result='".$SQL_result."'")); + } + /** + * Returns a DataObjectSet containing the subscribers who have never been sent this Newsletter + * + */ + function UnsentSubscribers() { + // Get a list of everyone who has been sent this newsletter + $sent_recipients = DataObject::get("Newsletter_SentRecipient","ParentID='".$this->ID."'"); + // If this Newsletter has not been sent to anyone yet, $sent_recipients will be null + if ($sent_recipients != null) { + $sent_recipients_array = $sent_recipients->toNestedArray('MemberID'); + } else { + $sent_recipients_array = array(); + } + + // Get a list of all the subscribers to this newsletter + $subscribers = DataObject::get( 'Member', "`GroupID`='".$this->Parent()->GroupID."'", null, "INNER JOIN `Group_Members` ON `MemberID`=`Member`.`ID`" ); + // If this Newsletter has no subscribers, $subscribers will be null + if ($subscribers != null) { + $subscribers_array = $subscribers->toNestedArray(); + } else { + $subscribers_array = array(); + } + + // Get list of subscribers who have not been sent this newsletter: + $unsent_subscribers_array = array_diff_key($subscribers_array, $sent_recipients_array); + + // Create new data object set containing the subscribers who have not been sent this newsletter: + $unsent_subscribers = new DataObjectSet(); + foreach($unsent_subscribers_array as $key => $data) { + $record = array( + 'ID' => $data['ID'], + 'FirstName' => $data['FirstName'], + 'Surname' => $data['Surname'], + 'Email' => $data['Email'] + ); + $unsent_subscribers->push(new ArrayData($record)); + } + + return $unsent_subscribers; + } + function getTitle() { return $this->getField('Subject'); } @@ -51,6 +105,7 @@ class Newsletter extends DataObject { static $has_many = array( "Recipients" => "Newsletter_Recipient", + "SentRecipients" => "Newsletter_SentRecipient", ); static function newDraft( $parentID, $subject, $content ) { @@ -69,6 +124,21 @@ class Newsletter extends DataObject { } } +class Newsletter_SentRecipient extends DataObject { + /** + * The DB schema for Newsletter_SentRecipient. + * + * ParentID is the the Newsletter + * Email and MemberID keep track of the recpients information + * Result has 3 possible values: "Sent", (mail() returned TRUE), "Failed" (mail() returned FALSE), or "Bounced" ({@see $email_bouncehandler}). + */ + static $db = array( + "ParentID" => "Int", + "Email" => "Varchar(255)", + "MemberID" => "Int", + "Result" => "Enum('Sent, Failed, Bounced', 'Sent')", + ); +} class Newsletter_Recipient extends DataObject { static $db = array( "ParentID" => "Int", diff --git a/code/Newsletter/NewsletterEmailProcess.php b/code/Newsletter/NewsletterEmailProcess.php index 8c086c13..90a710f6 100755 --- a/code/Newsletter/NewsletterEmailProcess.php +++ b/code/Newsletter/NewsletterEmailProcess.php @@ -29,7 +29,7 @@ class NewsletterEmailProcess extends BatchProcess { while($this->current < $max) { $index = $this->current++; $member = $this->objects[$index]; - + // check to see if the user has unsubscribed from the mailing list // TODO Join in the above query first $unsubscribeRecord = DataObject::get_one('Member_UnsubscribeRecord', "`MemberID`='{$member->ID}' AND `NewsletterTypeID`='{$this->nlType->ID}'"); @@ -59,7 +59,7 @@ class NewsletterEmailProcess extends BatchProcess { $e->populateTemplate( array( 'Member' => $member, 'FirstName' => $member->FirstName ) ); - $this->sendToAddress( $e, $address, $this->messageID ); + $this->sendToAddress( $e, $address, $this->messageID, $member); } } @@ -69,10 +69,29 @@ class NewsletterEmailProcess extends BatchProcess { return parent::next(); } - private function sendToAddress( $email, $address, $messageID = null ) { - $email->setTo( $address ); - $email->send( $messageID ); - } + /* + * Sends a Newsletter email to the specified address + * + * @param $member The object containing information about the member being emailed + */ + private function sendToAddress( $email, $address, $messageID = null, $member) { + $email->setTo( $address ); + $result = $email->send( $messageID ); + // Log result of the send + $newsletter = new Newsletter_SentRecipient(); + $newsletter->Email = $address; + $newsletter->MemberID = $member->ID; + // If Sending is successful + if ($result == true) { + $newsletter->Result = 'Sent'; + } else { + $newsletter->Result = 'Failed'; + } + $newsletter->ParentID = $this->newsletter->ID; + $newsletter->write(); + // Adding a pause between email sending can be useful for debugging purposes + // sleep(10); + } function complete() { parent::complete(); diff --git a/code/NewsletterAdmin.php b/code/NewsletterAdmin.php index 1a08c37c..525b1efd 100755 --- a/code/NewsletterAdmin.php +++ b/code/NewsletterAdmin.php @@ -326,7 +326,7 @@ class NewsletterAdmin extends LeftAndMain { * Reloads the list of recipients via ajax */ function getrecipientslist() { - if( $_REQUEST['ajax'] ) { + if(Director::is_ajax()) { $newsletterType = DataObject::get_by_id('NewsletterType', $this->urlParams['ID'] ); $fields = new FieldSet($memberList = new MemberTableField($this, "Recipients", $newsletterType->Group() )); $memberList->setController($this); @@ -336,6 +336,17 @@ class NewsletterAdmin extends LeftAndMain { } } + /** + * Reloads the "Sent Status Report" tab via ajax + */ + function getsentstatusreport($params) { + if(Director::is_ajax()) { + $newsletter = DataObject::get_by_id( 'Newsletter', $params['ID'] ); + $sent_status_report = $newsletter->renderWith("Newsletter_SentStatusReport"); + return $sent_status_report; + } + } + public static function template_path() { if(self::$template_path) return self::$template_path; else return self::$template_path = project() . '/templates/email'; diff --git a/javascript/NewsletterAdmin_right.js b/javascript/NewsletterAdmin_right.js index 28fb66eb..94953ec9 100755 --- a/javascript/NewsletterAdmin_right.js +++ b/javascript/NewsletterAdmin_right.js @@ -323,6 +323,17 @@ Behaviour.register({ // $('SendProgressBar').setText( 'Done!' ); $('SendProgressBar').reset(); // this.elements.Message.value = ''; + + // Reload the "Sent Status Report" tab after a Newsletter is sent + var id = this.elements.NewsletterID.value; + var request = new Ajax.Request(baseHref() + 'admin/newsletter/getsentstatusreport/' + id + '?ajax=1', { + onSuccess: function( response ) { + $('Root_SentStatusReport').innerHTML = response.responseText; + }, + onFailure: function(response) { + statusMessage('Could not automatically refresh Sent Status Report tab', 'bad'); + } + }); this.close(); if( response ) Ajax.Evaluator(response); @@ -359,6 +370,7 @@ Behaviour.register({ } }); +// @TODO: Check if this code is used anymore now that NewsletterList was removed. NewsletterList = Class.create(); NewsletterList.applyTo('table.NewsletterList'); NewsletterList.prototype = { diff --git a/templates/Newsletter_SentStatusReport.ss b/templates/Newsletter_SentStatusReport.ss new file mode 100644 index 00000000..3d8820bf --- /dev/null +++ b/templates/Newsletter_SentStatusReport.ss @@ -0,0 +1,93 @@ +<% if SentRecipients(Failed) %> +

Sending to the Following Recipients Failed

+ + + + + + + + + <% control SentRecipients(Failed) %> + + + + + + <% end_control %> + + +
Result
$Email$LastEdited$Result
+<% end_if %> +<% if SentRecipients(Bounced) %> +

Sending to the Following Recipients Bounced

+ + + + + + + + + + + <% control SentRecipients(Bounced) %> + + + + + + <% end_control %> + + +
DateResult
$Email$LastEdited$Result
+<% end_if %> + +<% if UnsentSubscribers %> +

The Newsletter has Never Been Sent to Following Subscribers

+ + + + + + + + + + + + <% control UnsentSubscribers %> + + + + + + <% end_control %> + + +
FirstnameSurname
$FirstName$Surname$Email
+<% end_if %> + +<% if SentRecipients(Sent) %> +

Sending to the Following Recipients was Successful

+ + + + + + + + + + + <% control SentRecipients(Sent) %> + + + + + + <% end_control %> + + +
DateResult
$Email$LastEdited$Result
+<% end_if %>