Ian province abbreviation patch - issue 724
[civicrm-core.git] / CRM / Mailing / Event / BAO / Subscribe.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 * $Id$
33 *
34 */
35
36
37require_once 'Mail/mime.php';
28518c90
EM
38
39/**
40 * Class CRM_Mailing_Event_BAO_Subscribe
41 */
6a488035
TO
42class CRM_Mailing_Event_BAO_Subscribe extends CRM_Mailing_Event_DAO_Subscribe {
43
44 /**
fe482240 45 * Class constructor.
6a488035 46 */
00be9182 47 public function __construct() {
6a488035
TO
48 parent::__construct();
49 }
50
51 /**
52 * Register a subscription event. Create a new contact if one does not
53 * already exist.
54 *
90c8230e
TO
55 * @param int $group_id
56 * The group id to subscribe to.
57 * @param string $email
58 * The email address of the (new) contact.
59 * @param int $contactId
60 * Currently used during event registration/contribution.
c490a46a
CW
61 * Specifically to avoid linking group to wrong duplicate contact
62 * during event registration.
63 * @param string $context
6a488035 64 *
72b3a70c
CW
65 * @return int|null
66 * $se_id The id of the subscription event, null on failure
6a488035
TO
67 */
68 public static function &subscribe($group_id, $email, $contactId = NULL, $context = NULL) {
69 // CRM-1797 - allow subscription only to public groups
70 $params = array('id' => (int) $group_id);
71 $defaults = array();
72 $contact_id = NULL;
73 $success = NULL;
74
75 $bao = CRM_Contact_BAO_Group::retrieve($params, $defaults);
76 if ($bao && substr($bao->visibility, 0, 6) != 'Public' && $context != 'profile') {
77 return $success;
78 }
79
80 $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
81 $email = $strtolower($email);
82
83 // process the query only if no contactId
84 if ($contactId) {
85 $contact_id = $contactId;
86 }
87 else {
88 /* First, find out if the contact already exists */
89
90 $query = "
91 SELECT DISTINCT contact_a.id as contact_id
92 FROM civicrm_contact contact_a
93LEFT JOIN civicrm_email ON contact_a.id = civicrm_email.contact_id
94 WHERE civicrm_email.email = %1 AND contact_a.is_deleted = 0";
95
96 $params = array(1 => array($email, 'String'));
97 $dao = CRM_Core_DAO::executeQuery($query, $params);
98 $id = array();
99 // lets just use the first contact id we got
100 if ($dao->fetch()) {
101 $contact_id = $dao->contact_id;
102 }
103 $dao->free();
104 }
105
106 $transaction = new CRM_Core_Transaction();
107
108 if (!$contact_id) {
109 require_once 'CRM/Utils/DeprecatedUtils.php';
110
111 /* If the contact does not exist, create one. */
112
113 $formatted = array(
114 'contact_type' => 'Individual',
115 'version' => 3,
116 );
117 $locationType = CRM_Core_BAO_LocationType::getDefault();
118 $value = array(
119 'email' => $email,
120 'location_type_id' => $locationType->id,
121 );
122 _civicrm_api3_deprecated_add_formatted_param($value, $formatted);
123
a05662ef 124 $formatted['onDuplicate'] = CRM_Import_Parser::DUPLICATE_SKIP;
6a488035
TO
125 $formatted['fixAddress'] = TRUE;
126 require_once 'api/api.php';
127 $contact = civicrm_api('contact', 'create', $formatted);
128 if (civicrm_error($contact)) {
129 return $success;
130 }
131 $contact_id = $contact['id'];
132 }
133 elseif (!is_numeric($contact_id) &&
134 (int ) $contact_id > 0
135 ) {
136 // make sure contact_id is numeric
137 return $success;
138 }
139
6a488035
TO
140 /* Get the primary email id from the contact to use as a hash input */
141
142 $dao = new CRM_Core_DAO();
143
144 $query = "
145SELECT civicrm_email.id as email_id
146 FROM civicrm_email
147 WHERE civicrm_email.email = %1
148 AND civicrm_email.contact_id = %2";
35f7561f 149 $params = array(
353ffa53 150 1 => array($email, 'String'),
6a488035
TO
151 2 => array($contact_id, 'Integer'),
152 );
153 $dao = CRM_Core_DAO::executeQuery($query, $params);
154
155 if (!$dao->fetch()) {
156 CRM_Core_Error::fatal('Please file an issue with the backtrace');
157 return $success;
158 }
159
160 $se = new CRM_Mailing_Event_BAO_Subscribe();
161 $se->group_id = $group_id;
162 $se->contact_id = $contact_id;
163 $se->time_stamp = date('YmdHis');
164 $se->hash = substr(sha1("{$group_id}:{$contact_id}:{$dao->email_id}:" . time()),
165 0, 16
166 );
167 $se->save();
168
169 $contacts = array($contact_id);
170 CRM_Contact_BAO_GroupContact::addContactsToGroup($contacts, $group_id,
171 'Email', 'Pending', $se->id
172 );
173
174 $transaction->commit();
175 return $se;
176 }
177
178 /**
fe482240 179 * Verify the hash of a subscription event.
6a488035 180 *
90c8230e
TO
181 * @param int $contact_id
182 * ID of the contact.
183 * @param int $subscribe_id
184 * ID of the subscription event.
185 * @param string $hash
186 * Hash to verify.
6a488035 187 *
72b3a70c
CW
188 * @return object|null
189 * The subscribe event object, or null on failure
6a488035
TO
190 */
191 public static function &verify($contact_id, $subscribe_id, $hash) {
192 $success = NULL;
193 $se = new CRM_Mailing_Event_BAO_Subscribe();
194 $se->contact_id = $contact_id;
195 $se->id = $subscribe_id;
196 $se->hash = $hash;
197 if ($se->find(TRUE)) {
198 $success = $se;
199 }
200 return $success;
201 }
202
203 /**
204 * Ask a contact for subscription confirmation (opt-in)
205 *
90c8230e
TO
206 * @param string $email
207 * The email address.
6a488035
TO
208 *
209 * @return void
6a488035
TO
210 */
211 public function send_confirm_request($email) {
212 $config = CRM_Core_Config::singleton();
213
214 $domain = CRM_Core_BAO_Domain::getDomain();
215
216 //get the default domain email address.
217 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
218
219 $localpart = CRM_Core_BAO_MailSettings::defaultLocalpart();
220 $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
221
222 $confirm = implode($config->verpSeparator,
353ffa53
TO
223 array(
224 $localpart . 'c',
225 $this->contact_id,
226 $this->id,
227 $this->hash,
228 )
229 ) . "@$emailDomain";
6a488035
TO
230
231 $group = new CRM_Contact_BAO_Group();
232 $group->id = $this->group_id;
233 $group->find(TRUE);
234
235 $component = new CRM_Mailing_BAO_Component();
236 $component->is_default = 1;
237 $component->is_active = 1;
238 $component->component_type = 'Subscribe';
239
240 $component->find(TRUE);
241
242 $headers = array(
243 'Subject' => $component->subject,
244 'From' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
245 'To' => $email,
246 'Reply-To' => $confirm,
247 'Return-Path' => "do-not-reply@$emailDomain",
248 );
249
250 $url = CRM_Utils_System::url('civicrm/mailing/confirm',
251 "reset=1&cid={$this->contact_id}&sid={$this->id}&h={$this->hash}",
252 TRUE
253 );
254
255 $html = $component->body_html;
256
257 if ($component->body_text) {
258 $text = $component->body_text;
259 }
260 else {
261 $text = CRM_Utils_String::htmlToText($component->body_html);
262 }
263
264 $bao = new CRM_Mailing_BAO_Mailing();
265 $bao->body_text = $text;
266 $bao->body_html = $html;
267 $tokens = $bao->getTokens();
268
269 $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html']);
270 $html = CRM_Utils_Token::replaceSubscribeTokens($html,
271 $group->title,
272 $url, TRUE
273 );
274
275 $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
276 $text = CRM_Utils_Token::replaceSubscribeTokens($text,
277 $group->title,
278 $url, FALSE
279 );
280 // render the &amp; entities in text mode, so that the links work
281 $text = str_replace('&amp;', '&', $text);
282
283 $message = new Mail_mime("\n");
284
285 $message->setHTMLBody($html);
286 $message->setTxtBody($text);
287 $b = CRM_Utils_Mail::setMimeParams($message);
288 $h = $message->headers($headers);
289 CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 's',
290 $this->contact_id,
291 $this->id,
292 $this->hash
293 );
247eb841 294 $mailer = \Civi\Core\Container::singleton()->get('pear_mail');
6a488035 295
6a488035 296 if (is_object($mailer)) {
6a4257d4 297 $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
6a488035 298 $mailer->send($email, $h, $b);
6a4257d4 299 unset($errorScope);
6a488035
TO
300 }
301 }
302
303 /**
fe482240 304 * Get the domain object given a subscribe event.
6a488035 305 *
90c8230e
TO
306 * @param int $subscribe_id
307 * ID of the subscribe event.
6a488035 308 *
a6c01b45
CW
309 * @return object
310 * $domain The domain owning the event
6a488035
TO
311 */
312 public static function &getDomain($subscribe_id) {
313 return CRM_Core_BAO_Domain::getDomain();
314 }
315
316 /**
fe482240 317 * Get the group details to which given email belongs.
6a488035 318 *
90c8230e
TO
319 * @param string $email
320 * Email of the contact.
321 * @param int $contactID
322 * ContactID if we want an exact match.
6a488035 323 *
a6c01b45
CW
324 * @return array
325 * array of group ids
6a488035 326 */
2dd4cf8e 327 public static function getContactGroups($email, $contactID = NULL) {
6a488035
TO
328 if ($contactID) {
329 $query = "
330 SELECT DISTINCT group_a.group_id, group_a.status, civicrm_group.title
331 FROM civicrm_group_contact group_a
332 LEFT JOIN civicrm_group ON civicrm_group.id = group_a.group_id
333 LEFT JOIN civicrm_contact ON ( group_a.contact_id = civicrm_contact.id )
334 WHERE civicrm_contact.id = %1";
335
336 $params = array(1 => array($contactID, 'Integer'));
337 }
338 else {
339 $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
340 $email = $strtolower($email);
341
342 $query = "
343 SELECT DISTINCT group_a.group_id, group_a.status, civicrm_group.title
344 FROM civicrm_group_contact group_a
345 LEFT JOIN civicrm_group ON civicrm_group.id = group_a.group_id
346 LEFT JOIN civicrm_contact ON ( group_a.contact_id = civicrm_contact.id ) AND civicrm_contact.is_deleted = 0
347 LEFT JOIN civicrm_email ON civicrm_contact.id = civicrm_email.contact_id
348 WHERE civicrm_email.email = %1";
349
350 $params = array(1 => array($email, 'String'));
351 }
352
353 $dao = CRM_Core_DAO::executeQuery($query, $params);
354 $groups = array();
355 while ($dao->fetch()) {
356 $groups[$dao->group_id] = array(
357 'id' => $dao->group_id,
358 'title' => $dao->title,
359 'status' => $dao->status,
360 );
361 }
362
363 $dao->free();
364 return $groups;
365 }
366
367 /**
fe482240 368 * Send subscribe mail.
6a488035 369 *
90c8230e
TO
370 * @param array $groups
371 * The list of group ids for subscribe.
372 * @param array $params
373 * The list of email.
374 * @param int $contactId
375 * Currently used during event registration/contribution.
16b10e64
CW
376 * Specifically to avoid linking group to wrong duplicate contact
377 * during event registration.
c490a46a 378 * @param string $context
77b97be7 379 *
6a488035 380 * @return void
6a488035
TO
381 */
382 public static function commonSubscribe(&$groups, &$params, $contactId = NULL, $context = NULL) {
383 $contactGroups = CRM_Mailing_Event_BAO_Subscribe::getContactGroups($params['email'], $contactId);
384 $group = array();
385 $success = NULL;
386 foreach ($groups as $groupID) {
387 $title = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $groupID, 'title');
388 if (array_key_exists($groupID, $contactGroups) && $contactGroups[$groupID]['status'] != 'Removed') {
389 $group[$groupID]['title'] = $contactGroups[$groupID]['title'];
390
391 $group[$groupID]['status'] = $contactGroups[$groupID]['status'];
353ffa53
TO
392 $status = ts('You are already subscribed in %1, your subscription is %2.', array(
393 1 => $group[$groupID]['title'],
1f006819 394 2 => ts($group[$groupID]['status']),
353ffa53 395 ));
6a488035
TO
396 CRM_Utils_System::setUFMessage($status);
397 continue;
398 }
399
400 $se = self::subscribe($groupID,
401 $params['email'], $contactId, $context
402 );
403 if ($se !== NULL) {
404 $success = TRUE;
405 $groupAdded[] = $title;
406
c490a46a 407 // Ask the contact for confirmation
6a488035
TO
408 $se->send_confirm_request($params['email']);
409 }
410 else {
411 $success = FALSE;
412 $groupFailed[] = $title;
413 }
414 }
415 if ($success) {
e93afd65
DG
416 $groupTitle = implode(', ', $groupAdded);
417 CRM_Utils_System::setUFMessage(ts('Your subscription request has been submitted for %1. Check your inbox shortly for the confirmation email(s). If you do not see a confirmation email, please check your spam/junk mail folder.', array(1 => $groupTitle)));
6a488035
TO
418 }
419 elseif ($success === FALSE) {
420 $groupTitle = implode(',', $groupFailed);
e93afd65 421 CRM_Utils_System::setUFMessage(ts('We had a problem processing your subscription request for %1. You have tried to subscribe to a private group and/or we encountered a database error. Please contact the site administrator.', array(1 => $groupTitle)));
6a488035
TO
422 }
423 }
96025800 424
6a488035 425}