3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
36 require_once 'Mail/mime.php';
37 class CRM_Mailing_Event_BAO_Unsubscribe
extends CRM_Mailing_Event_DAO_Unsubscribe
{
42 function __construct() {
43 parent
::__construct();
47 * Unsubscribe a contact from the domain
49 * @param int $job_id The job ID
50 * @param int $queue_id The Queue Event ID of the recipient
51 * @param string $hash The hash
53 * @return boolean Was the contact successfully unsubscribed?
57 public static function unsub_from_domain($job_id, $queue_id, $hash) {
58 $q = CRM_Mailing_Event_BAO_Queue
::verify($job_id, $queue_id, $hash);
63 $transaction = new CRM_Core_Transaction();
65 $now = date('YmdHis');
66 if (CRM_Core_BAO_Email
::isMultipleBulkMail()) {
67 $email = new CRM_Core_BAO_Email();
68 $email->id
= $q->email_id
;
69 if ($email->find(TRUE)) {
76 $sqlParams = array(1 => array($now, 'Timestamp'),
77 2 => array($email->email
, 'String'),
79 CRM_Core_DAO
::executeQuery($sql, $sqlParams);
83 $contact = new CRM_Contact_BAO_Contact();
84 $contact->id
= $q->contact_id
;
85 $contact->is_opt_out
= TRUE;
89 $ue = new CRM_Mailing_Event_BAO_Unsubscribe();
90 $ue->event_queue_id
= $queue_id;
91 $ue->org_unsubscribe
= 1;
92 $ue->time_stamp
= $now;
96 'contact_id' => $q->contact_id
,
98 'status' => 'Removed',
100 'tracking' => $ue->id
,
102 CRM_Contact_BAO_SubscriptionHistory
::create($shParams);
104 $transaction->commit();
110 * Unsubscribe a contact from all groups that received this mailing
112 * @param int $job_id The job ID
113 * @param int $queue_id The Queue Event ID of the recipient
114 * @param string $hash The hash
115 * @param boolean $return If true return the list of groups.
117 * @return array|null $groups Array of all groups from which the contact was removed, or null if the queue event could not be found.
121 public static function &unsub_from_mailing($job_id, $queue_id, $hash, $return = FALSE) {
122 /* First make sure there's a matching queue event */
124 $q = CRM_Mailing_Event_BAO_Queue
::verify($job_id, $queue_id, $hash);
130 $contact_id = $q->contact_id
;
131 $transaction = new CRM_Core_Transaction();
133 $do = new CRM_Core_DAO();
134 $mgObject = new CRM_Mailing_DAO_MailingGroup();
135 $mg = $mgObject->getTableName();
136 $jobObject = new CRM_Mailing_BAO_MailingJob();
137 $job = $jobObject->getTableName();
138 $mailingObject = new CRM_Mailing_BAO_Mailing();
139 $mailing = $mailingObject->getTableName();
140 $groupObject = new CRM_Contact_BAO_Group();
141 $group = $groupObject->getTableName();
142 $gcObject = new CRM_Contact_BAO_GroupContact();
143 $gc = $gcObject->getTableName();
145 //We Need the mailing Id for the hook...
146 $do->query("SELECT $job.mailing_id as mailing_id
148 WHERE $job.id = " . CRM_Utils_Type
::escape($job_id, 'Integer'));
150 $mailing_id = $do->mailing_id
;
153 SELECT $mg.entity_table as entity_table,
154 $mg.entity_id as entity_id,
155 $mg.group_type as group_type
158 ON $job.mailing_id = $mg.mailing_id
160 ON $mg.entity_id = $group.id
161 WHERE $job.id = " . CRM_Utils_Type
::escape($job_id, 'Integer') . "
162 AND $mg.group_type IN ('Include', 'Base')
163 AND $group.is_hidden = 0"
166 /* Make a list of groups and a list of prior mailings that received
171 $base_groups = array();
174 while ($do->fetch()) {
175 if ($do->entity_table
== $group) {
176 if ($do->group_type
== 'Base') {
177 $base_groups[$do->entity_id
] = NULL;
180 $groups[$do->entity_id
] = NULL;
183 elseif ($do->entity_table
== $mailing) {
184 $mailings[] = $do->entity_id
;
188 /* As long as we have prior mailings, find their groups and add to the
191 while (!empty($mailings)) {
193 SELECT $mg.entity_table as entity_table,
194 $mg.entity_id as entity_id
196 WHERE $mg.mailing_id IN (" . implode(', ', $mailings) . ")
197 AND $mg.group_type = 'Include'");
201 while ($do->fetch()) {
202 if ($do->entity_table
== $group) {
203 $groups[$do->entity_id
] = TRUE;
205 elseif ($do->entity_table
== $mailing) {
206 $mailings[] = $do->entity_id
;
211 //Pass the groups to be unsubscribed from through a hook.
212 $group_ids = array_keys($groups);
213 $base_group_ids = array_keys($base_groups);
214 CRM_Utils_Hook
::unsubscribeGroups('unsubscribe', $mailing_id, $contact_id, $group_ids, $base_group_ids);
216 /* Now we have a complete list of recipient groups. Filter out all
217 * those except smart groups, those that the contact belongs to and
218 * base groups from search based mailings */
220 $baseGroupClause = '';
221 if (!empty($base_group_ids)) {
222 $baseGroupClause = "OR $group.id IN(" . implode(', ', $base_group_ids) . ")";
225 SELECT $group.id as group_id,
226 $group.title as title,
227 $group.description as description
230 ON $gc.group_id = $group.id
231 WHERE $group.id IN (" . implode(', ', array_merge($group_ids, $base_group_ids)) . ")
232 AND $group.is_hidden = 0
233 AND ($group.saved_search_id is not null
234 OR ($gc.contact_id = $contact_id
235 AND $gc.status = 'Added')
240 $returnGroups = array();
241 while ($do->fetch()) {
242 $returnGroups[$do->group_id
] = array(
243 'title' => $do->title
,
244 'description' => $do->description
,
247 return $returnGroups;
250 while ($do->fetch()) {
251 $groups[$do->group_id
] = $do->title
;
255 $contacts = array($contact_id);
256 foreach ($groups as $group_id => $group_name) {
259 if (in_array($group_id, $base_group_ids)) {
260 list($total, $removed, $notremoved) = CRM_Contact_BAO_GroupContact
::addContactsToGroup($contacts, $group_id, 'Email', 'Removed');
263 list($total, $removed, $notremoved) = CRM_Contact_BAO_GroupContact
::removeContactsFromGroup($contacts, $group_id, 'Email');
267 unset($groups[$group_id]);
271 $ue = new CRM_Mailing_Event_BAO_Unsubscribe();
272 $ue->event_queue_id
= $queue_id;
273 $ue->org_unsubscribe
= 0;
274 $ue->time_stamp
= date('YmdHis');
277 $transaction->commit();
282 * Send a reponse email informing the contact of the groups from which he
283 * has been unsubscribed.
285 * @param string $queue_id The queue event ID
286 * @param array $groups List of group IDs
287 * @param bool $is_domain Is this domain-level?
288 * @param int $job The job ID
294 public static function send_unsub_response($queue_id, $groups, $is_domain = FALSE, $job) {
295 $config = CRM_Core_Config
::singleton();
296 $domain = CRM_Core_BAO_Domain
::getDomain();
298 $jobObject = new CRM_Mailing_BAO_MailingJob();
299 $jobTable = $jobObject->getTableName();
300 $mailingObject = new CRM_Mailing_DAO_Mailing();
301 $mailingTable = $mailingObject->getTableName();
302 $contactsObject = new CRM_Contact_DAO_Contact();
303 $contacts = $contactsObject->getTableName();
304 $emailObject = new CRM_Core_DAO_Email();
305 $email = $emailObject->getTableName();
306 $queueObject = new CRM_Mailing_Event_BAO_Queue();
307 $queue = $queueObject->getTableName();
309 //get the default domain email address.
310 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain
::getNameAndEmail();
312 $dao = new CRM_Mailing_BAO_Mailing();
313 $dao->query(" SELECT * FROM $mailingTable
314 INNER JOIN $jobTable ON
315 $jobTable.mailing_id = $mailingTable.id
316 WHERE $jobTable.id = $job");
319 $component = new CRM_Mailing_BAO_Component();
322 $component->id
= $dao->optout_id
;
325 $component->id
= $dao->unsubscribe_id
;
327 $component->find(TRUE);
329 $html = $component->body_html
;
330 if ($component->body_text
) {
331 $text = $component->body_text
;
334 $text = CRM_Utils_String
::htmlToText($component->body_html
);
337 $eq = new CRM_Core_DAO();
339 "SELECT $contacts.preferred_mail_format as format,
340 $contacts.id as contact_id,
341 $email.email as email,
344 INNER JOIN $queue ON $queue.contact_id = $contacts.id
345 INNER JOIN $email ON $queue.email_id = $email.id
346 WHERE $queue.id = " . CRM_Utils_Type
::escape($queue_id, 'Integer')
351 foreach ($groups as $key => $value) {
353 unset($groups[$key]);
358 $message = new Mail_mime("\n");
360 list($addresses, $urls) = CRM_Mailing_BAO_Mailing
::getVerpAndUrls($job, $queue_id, $eq->hash
, $eq->email
);
361 $bao = new CRM_Mailing_BAO_Mailing();
362 $bao->body_text
= $text;
363 $bao->body_html
= $html;
364 $tokens = $bao->getTokens();
365 if ($eq->format
== 'HTML' ||
$eq->format
== 'Both') {
366 $html = CRM_Utils_Token
::replaceDomainTokens($html, $domain, TRUE, $tokens['html']);
367 $html = CRM_Utils_Token
::replaceUnsubscribeTokens($html, $domain, $groups, TRUE, $eq->contact_id
, $eq->hash
);
368 $html = CRM_Utils_Token
::replaceActionTokens($html, $addresses, $urls, TRUE, $tokens['html']);
369 $html = CRM_Utils_Token
::replaceMailingTokens($html, $dao, NULL, $tokens['html']);
370 $message->setHTMLBody($html);
372 if (!$html ||
$eq->format
== 'Text' ||
$eq->format
== 'Both') {
373 $text = CRM_Utils_Token
::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
374 $text = CRM_Utils_Token
::replaceUnsubscribeTokens($text, $domain, $groups, FALSE, $eq->contact_id
, $eq->hash
);
375 $text = CRM_Utils_Token
::replaceActionTokens($text, $addresses, $urls, FALSE, $tokens['text']);
376 $text = CRM_Utils_Token
::replaceMailingTokens($text, $dao, NULL, $tokens['text']);
377 $message->setTxtBody($text);
380 $emailDomain = CRM_Core_BAO_MailSettings
::defaultDomain();
383 'Subject' => $component->subject
,
384 'From' => "\"$domainEmailName\" <do-not-reply@$emailDomain>",
386 'Reply-To' => "do-not-reply@$emailDomain",
387 'Return-Path' => "do-not-reply@$emailDomain",
389 CRM_Mailing_BAO_Mailing
::addMessageIdHeader($headers, 'u', $job, $queue_id, $eq->hash
);
391 $b = CRM_Utils_Mail
::setMimeParams($message);
392 $h = $message->headers($headers);
394 $mailer = $config->getMailer();
396 if (is_object($mailer)) {
397 $errorScope = CRM_Core_TemporaryErrorScope
::ignoreException();
398 $mailer->send($eq->email
, $h, $b);
404 * Get row count for the event selector
406 * @param int $mailing_id ID of the mailing
407 * @param int $job_id Optional ID of a job to filter on
408 * @param boolean $is_distinct Group by queue ID?
410 * @param null $org_unsubscribe
412 * @return int Number of rows in result set
416 public static function getTotalCount($mailing_id, $job_id = NULL,
417 $is_distinct = FALSE, $org_unsubscribe = NULL
419 $dao = new CRM_Core_DAO();
421 $unsub = self
::$_tableName;
422 $queueObject = new CRM_Mailing_Event_BAO_Queue();
423 $queue = $queueObject->getTableName();
424 $mailingObject = new CRM_Mailing_BAO_Mailing();
425 $mailing = $mailingObject->getTableName();
426 $jobObject = new CRM_Mailing_BAO_MailingJob();
427 $job = $jobObject->getTableName();
430 SELECT COUNT($unsub.id) as unsubs
433 ON $unsub.event_queue_id = $queue.id
435 ON $queue.job_id = $job.id
437 ON $job.mailing_id = $mailing.id
439 WHERE $mailing.id = " . CRM_Utils_Type
::escape($mailing_id, 'Integer');
441 if (!empty($job_id)) {
442 $query .= " AND $job.id = " . CRM_Utils_Type
::escape($job_id, 'Integer');
445 if ($org_unsubscribe !== NULL) {
446 $query .= " AND $unsub.org_unsubscribe = " . ($org_unsubscribe ?
0 : 1);
450 $query .= " GROUP BY $queue.id ";
459 return $dao->unsubs ?
$dao->unsubs
: 0;
464 * Get rows for the event browser
466 * @param int $mailing_id ID of the mailing
467 * @param int $job_id optional ID of the job
468 * @param boolean $is_distinct Group by queue id?
469 * @param int $offset Offset
470 * @param int $rowCount Number of rows
471 * @param array $sort sort array
473 * @param null $org_unsubscribe
474 * @return array Result set
478 public static function &getRows($mailing_id, $job_id = NULL,
479 $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL,
480 $org_unsubscribe = NULL
483 $dao = new CRM_Core_Dao();
485 $unsub = self
::$_tableName;
486 $queueObject = new CRM_Mailing_Event_BAO_Queue();
487 $queue = $queueObject->getTableName();
488 $mailingObject = new CRM_Mailing_BAO_Mailing();
489 $mailing = $mailingObject->getTableName();
490 $jobObject = new CRM_Mailing_BAO_MailingJob();
491 $job = $jobObject->getTableName();
492 $contactObject = new CRM_Contact_BAO_Contact();
493 $contact = $contactObject->getTableName();
494 $emailObject = new CRM_Core_BAO_Email();
495 $email = $emailObject->getTableName();
498 SELECT $contact.display_name as display_name,
499 $contact.id as contact_id,
500 $email.email as email,
501 $unsub.time_stamp as date,
502 $unsub.org_unsubscribe as org_unsubscribe
505 ON $queue.contact_id = $contact.id
507 ON $queue.email_id = $email.id
509 ON $unsub.event_queue_id = $queue.id
511 ON $queue.job_id = $job.id
513 ON $job.mailing_id = $mailing.id
515 WHERE $mailing.id = " . CRM_Utils_Type
::escape($mailing_id, 'Integer');
517 if (!empty($job_id)) {
518 $query .= " AND $job.id = " . CRM_Utils_Type
::escape($job_id, 'Integer');
521 if ($org_unsubscribe !== NULL) {
522 $query .= " AND $unsub.org_unsubscribe = " . ($org_unsubscribe ?
0 : 1);
526 $query .= " GROUP BY $queue.id ";
529 $orderBy = "sort_name ASC, {$unsub}.time_stamp DESC";
531 if (is_string($sort)) {
532 $sort = CRM_Utils_Type
::escape($sort, 'String');
536 $orderBy = trim($sort->orderBy());
540 $query .= " ORDER BY {$orderBy} ";
542 if ($offset ||
$rowCount) {
543 //Added "||$rowCount" to avoid displaying all records on first page
544 $query .= ' LIMIT ' . CRM_Utils_Type
::escape($offset, 'Integer') . ', ' . CRM_Utils_Type
::escape($rowCount, 'Integer');
551 while ($dao->fetch()) {
552 $url = CRM_Utils_System
::url('civicrm/contact/view',
553 "reset=1&cid={$dao->contact_id}"
556 'name' => "<a href=\"$url\">{$dao->display_name}</a>",
557 'email' => $dao->email
,
558 'org' => $dao->org_unsubscribe ?
ts('Yes') : ts('No'),
559 'date' => CRM_Utils_Date
::customFormat($dao->date
),
565 public static function getContactInfo($queueID) {
567 SELECT DISTINCT(civicrm_mailing_event_queue.contact_id) as contact_id,
568 civicrm_contact.display_name as display_name
569 civicrm_email.email as email
570 FROM civicrm_mailing_event_queue,
573 WHERE civicrm_mailing_event_queue.contact_id = civicrm_contact.id
574 AND civicrm_mailing_event_queue.email_id = civicrm_email.id
575 AND civicrm_mailing_event_queue.id = " . CRM_Utils_Type
::escape($queueID, 'Integer');
577 $dao = CRM_Core_DAO
::executeQuery($query, CRM_Core_DAO
::$_nullArray);
579 $displayName = 'Unknown';
582 $displayName = $dao->display_name
;
583 $email = $dao->email
;
586 return array($displayName, $email);