407 lines
13 KiB
PHP
407 lines
13 KiB
PHP
|
<?php
|
||
|
/*
|
||
|
+--------------------------------------------------------------------+
|
||
|
| CiviCRM version 4.7 |
|
||
|
+--------------------------------------------------------------------+
|
||
|
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||
|
+--------------------------------------------------------------------+
|
||
|
| This file is a part of CiviCRM. |
|
||
|
| |
|
||
|
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||
|
| under the terms of the GNU Affero General Public License |
|
||
|
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||
|
| |
|
||
|
| CiviCRM is distributed in the hope that it will be useful, but |
|
||
|
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||
|
| See the GNU Affero General Public License for more details. |
|
||
|
| |
|
||
|
| You should have received a copy of the GNU Affero General Public |
|
||
|
| License and the CiviCRM Licensing Exception along |
|
||
|
| with this program; if not, contact CiviCRM LLC |
|
||
|
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||
|
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||
|
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||
|
+--------------------------------------------------------------------+
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @package CRM
|
||
|
* @copyright CiviCRM LLC (c) 2004-2017
|
||
|
*/
|
||
|
|
||
|
|
||
|
require_once 'Mail/mime.php';
|
||
|
|
||
|
/**
|
||
|
* Class CRM_Mailing_Event_BAO_Subscribe
|
||
|
*/
|
||
|
class CRM_Mailing_Event_BAO_Subscribe extends CRM_Mailing_Event_DAO_Subscribe {
|
||
|
|
||
|
/**
|
||
|
* Class constructor.
|
||
|
*/
|
||
|
public function __construct() {
|
||
|
parent::__construct();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register a subscription event. Create a new contact if one does not
|
||
|
* already exist.
|
||
|
*
|
||
|
* @param int $group_id
|
||
|
* The group id to subscribe to.
|
||
|
* @param string $email
|
||
|
* The email address of the (new) contact.
|
||
|
* @param int $contactId
|
||
|
* Currently used during event registration/contribution.
|
||
|
* Specifically to avoid linking group to wrong duplicate contact
|
||
|
* during event registration.
|
||
|
* @param string $context
|
||
|
*
|
||
|
* @return int|null
|
||
|
* $se_id The id of the subscription event, null on failure
|
||
|
*/
|
||
|
public static function &subscribe($group_id, $email, $contactId = NULL, $context = NULL) {
|
||
|
// CRM-1797 - allow subscription only to public groups
|
||
|
$params = array('id' => (int) $group_id);
|
||
|
$defaults = array();
|
||
|
$contact_id = NULL;
|
||
|
$success = NULL;
|
||
|
|
||
|
$bao = CRM_Contact_BAO_Group::retrieve($params, $defaults);
|
||
|
if ($bao && substr($bao->visibility, 0, 6) != 'Public' && $context != 'profile') {
|
||
|
return $success;
|
||
|
}
|
||
|
|
||
|
$strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
|
||
|
$email = $strtolower($email);
|
||
|
|
||
|
// process the query only if no contactId
|
||
|
if ($contactId) {
|
||
|
$contact_id = $contactId;
|
||
|
}
|
||
|
else {
|
||
|
// First, find out if the contact already exists.
|
||
|
|
||
|
$query = "
|
||
|
SELECT DISTINCT contact_a.id as contact_id
|
||
|
FROM civicrm_contact contact_a
|
||
|
LEFT JOIN civicrm_email ON contact_a.id = civicrm_email.contact_id
|
||
|
WHERE civicrm_email.email = %1 AND contact_a.is_deleted = 0";
|
||
|
|
||
|
$params = array(1 => array($email, 'String'));
|
||
|
$dao = CRM_Core_DAO::executeQuery($query, $params);
|
||
|
// lets just use the first contact id we got
|
||
|
if ($dao->fetch()) {
|
||
|
$contact_id = $dao->contact_id;
|
||
|
}
|
||
|
$dao->free();
|
||
|
}
|
||
|
|
||
|
$transaction = new CRM_Core_Transaction();
|
||
|
|
||
|
if (!$contact_id) {
|
||
|
$locationType = CRM_Core_BAO_LocationType::getDefault();
|
||
|
$formatted = array(
|
||
|
'contact_type' => 'Individual',
|
||
|
'email' => $email,
|
||
|
'location_type_id' => $locationType->id,
|
||
|
);
|
||
|
|
||
|
$formatted['onDuplicate'] = CRM_Import_Parser::DUPLICATE_SKIP;
|
||
|
$formatted['fixAddress'] = TRUE;
|
||
|
$contact = civicrm_api3('contact', 'create', $formatted);
|
||
|
if (civicrm_error($contact)) {
|
||
|
return $success;
|
||
|
}
|
||
|
$contact_id = $contact['id'];
|
||
|
}
|
||
|
elseif (!is_numeric($contact_id) &&
|
||
|
(int ) $contact_id > 0
|
||
|
) {
|
||
|
// make sure contact_id is numeric
|
||
|
return $success;
|
||
|
}
|
||
|
|
||
|
// Get the primary email id from the contact to use as a hash input.
|
||
|
$query = "
|
||
|
SELECT civicrm_email.id as email_id
|
||
|
FROM civicrm_email
|
||
|
WHERE civicrm_email.email = %1
|
||
|
AND civicrm_email.contact_id = %2";
|
||
|
$params = array(
|
||
|
1 => array($email, 'String'),
|
||
|
2 => array($contact_id, 'Integer'),
|
||
|
);
|
||
|
$dao = CRM_Core_DAO::executeQuery($query, $params);
|
||
|
|
||
|
if (!$dao->fetch()) {
|
||
|
CRM_Core_Error::fatal('Please file an issue with the backtrace');
|
||
|
return $success;
|
||
|
}
|
||
|
|
||
|
$se = new CRM_Mailing_Event_BAO_Subscribe();
|
||
|
$se->group_id = $group_id;
|
||
|
$se->contact_id = $contact_id;
|
||
|
$se->time_stamp = date('YmdHis');
|
||
|
$se->hash = substr(sha1("{$group_id}:{$contact_id}:{$dao->email_id}:" . time()),
|
||
|
0, 16
|
||
|
);
|
||
|
$se->save();
|
||
|
|
||
|
$contacts = array($contact_id);
|
||
|
CRM_Contact_BAO_GroupContact::addContactsToGroup($contacts, $group_id,
|
||
|
'Email', 'Pending', $se->id
|
||
|
);
|
||
|
|
||
|
$transaction->commit();
|
||
|
return $se;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Verify the hash of a subscription event.
|
||
|
*
|
||
|
* @param int $contact_id
|
||
|
* ID of the contact.
|
||
|
* @param int $subscribe_id
|
||
|
* ID of the subscription event.
|
||
|
* @param string $hash
|
||
|
* Hash to verify.
|
||
|
*
|
||
|
* @return object|null
|
||
|
* The subscribe event object, or null on failure
|
||
|
*/
|
||
|
public static function &verify($contact_id, $subscribe_id, $hash) {
|
||
|
$success = NULL;
|
||
|
$se = new CRM_Mailing_Event_BAO_Subscribe();
|
||
|
$se->contact_id = $contact_id;
|
||
|
$se->id = $subscribe_id;
|
||
|
$se->hash = $hash;
|
||
|
if ($se->find(TRUE)) {
|
||
|
$success = $se;
|
||
|
}
|
||
|
return $success;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ask a contact for subscription confirmation (opt-in)
|
||
|
*
|
||
|
* @param string $email
|
||
|
* The email address.
|
||
|
*/
|
||
|
public function send_confirm_request($email) {
|
||
|
$config = CRM_Core_Config::singleton();
|
||
|
|
||
|
$domain = CRM_Core_BAO_Domain::getDomain();
|
||
|
|
||
|
//get the default domain email address.
|
||
|
list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
|
||
|
|
||
|
$localpart = CRM_Core_BAO_MailSettings::defaultLocalpart();
|
||
|
$emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
|
||
|
|
||
|
$confirm = implode($config->verpSeparator,
|
||
|
array(
|
||
|
$localpart . 'c',
|
||
|
$this->contact_id,
|
||
|
$this->id,
|
||
|
$this->hash,
|
||
|
)
|
||
|
) . "@$emailDomain";
|
||
|
|
||
|
$group = new CRM_Contact_BAO_Group();
|
||
|
$group->id = $this->group_id;
|
||
|
$group->find(TRUE);
|
||
|
|
||
|
$component = new CRM_Mailing_BAO_Component();
|
||
|
$component->is_default = 1;
|
||
|
$component->is_active = 1;
|
||
|
$component->component_type = 'Subscribe';
|
||
|
|
||
|
$component->find(TRUE);
|
||
|
|
||
|
$headers = array(
|
||
|
'Subject' => $component->subject,
|
||
|
'From' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
|
||
|
'To' => $email,
|
||
|
'Reply-To' => $confirm,
|
||
|
'Return-Path' => "do-not-reply@$emailDomain",
|
||
|
);
|
||
|
|
||
|
$url = CRM_Utils_System::url('civicrm/mailing/confirm',
|
||
|
"reset=1&cid={$this->contact_id}&sid={$this->id}&h={$this->hash}",
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
$html = $component->body_html;
|
||
|
|
||
|
if ($component->body_text) {
|
||
|
$text = $component->body_text;
|
||
|
}
|
||
|
else {
|
||
|
$text = CRM_Utils_String::htmlToText($component->body_html);
|
||
|
}
|
||
|
|
||
|
$bao = new CRM_Mailing_BAO_Mailing();
|
||
|
$bao->body_text = $text;
|
||
|
$bao->body_html = $html;
|
||
|
$tokens = $bao->getTokens();
|
||
|
|
||
|
$html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html']);
|
||
|
$html = CRM_Utils_Token::replaceSubscribeTokens($html,
|
||
|
$group->title,
|
||
|
$url, TRUE
|
||
|
);
|
||
|
|
||
|
$text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
|
||
|
$text = CRM_Utils_Token::replaceSubscribeTokens($text,
|
||
|
$group->title,
|
||
|
$url, FALSE
|
||
|
);
|
||
|
// render the & entities in text mode, so that the links work
|
||
|
$text = str_replace('&', '&', $text);
|
||
|
|
||
|
$message = new Mail_mime("\n");
|
||
|
|
||
|
$message->setHTMLBody($html);
|
||
|
$message->setTxtBody($text);
|
||
|
$b = CRM_Utils_Mail::setMimeParams($message);
|
||
|
$h = $message->headers($headers);
|
||
|
CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 's',
|
||
|
$this->contact_id,
|
||
|
$this->id,
|
||
|
$this->hash
|
||
|
);
|
||
|
$mailer = \Civi::service('pear_mail');
|
||
|
|
||
|
if (is_object($mailer)) {
|
||
|
$errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
|
||
|
$mailer->send($email, $h, $b);
|
||
|
unset($errorScope);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the domain object given a subscribe event.
|
||
|
*
|
||
|
* @param int $subscribe_id
|
||
|
* ID of the subscribe event.
|
||
|
*
|
||
|
* @return object
|
||
|
* $domain The domain owning the event
|
||
|
*/
|
||
|
public static function &getDomain($subscribe_id) {
|
||
|
return CRM_Core_BAO_Domain::getDomain();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the group details to which given email belongs.
|
||
|
*
|
||
|
* @param string $email
|
||
|
* Email of the contact.
|
||
|
* @param int $contactID
|
||
|
* ContactID if we want an exact match.
|
||
|
*
|
||
|
* @return array
|
||
|
* array of group ids
|
||
|
*/
|
||
|
public static function getContactGroups($email, $contactID = NULL) {
|
||
|
if ($contactID) {
|
||
|
$query = "
|
||
|
SELECT DISTINCT group_a.group_id, group_a.status, civicrm_group.title
|
||
|
FROM civicrm_group_contact group_a
|
||
|
LEFT JOIN civicrm_group ON civicrm_group.id = group_a.group_id
|
||
|
LEFT JOIN civicrm_contact ON ( group_a.contact_id = civicrm_contact.id )
|
||
|
WHERE civicrm_contact.id = %1";
|
||
|
|
||
|
$params = array(1 => array($contactID, 'Integer'));
|
||
|
}
|
||
|
else {
|
||
|
$strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
|
||
|
$email = $strtolower($email);
|
||
|
|
||
|
$query = "
|
||
|
SELECT DISTINCT group_a.group_id, group_a.status, civicrm_group.title
|
||
|
FROM civicrm_group_contact group_a
|
||
|
LEFT JOIN civicrm_group ON civicrm_group.id = group_a.group_id
|
||
|
LEFT JOIN civicrm_contact ON ( group_a.contact_id = civicrm_contact.id ) AND civicrm_contact.is_deleted = 0
|
||
|
LEFT JOIN civicrm_email ON civicrm_contact.id = civicrm_email.contact_id
|
||
|
WHERE civicrm_email.email = %1";
|
||
|
|
||
|
$params = array(1 => array($email, 'String'));
|
||
|
}
|
||
|
|
||
|
$dao = CRM_Core_DAO::executeQuery($query, $params);
|
||
|
$groups = array();
|
||
|
while ($dao->fetch()) {
|
||
|
$groups[$dao->group_id] = array(
|
||
|
'id' => $dao->group_id,
|
||
|
'title' => $dao->title,
|
||
|
'status' => $dao->status,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$dao->free();
|
||
|
return $groups;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send subscribe mail.
|
||
|
*
|
||
|
* @param array $groups
|
||
|
* The list of group ids for subscribe.
|
||
|
* @param array $params
|
||
|
* The list of email.
|
||
|
* @param int $contactId
|
||
|
* Currently used during event registration/contribution.
|
||
|
* Specifically to avoid linking group to wrong duplicate contact
|
||
|
* during event registration.
|
||
|
* @param string $context
|
||
|
*/
|
||
|
public static function commonSubscribe(&$groups, &$params, $contactId = NULL, $context = NULL) {
|
||
|
$contactGroups = CRM_Mailing_Event_BAO_Subscribe::getContactGroups($params['email'], $contactId);
|
||
|
$group = array();
|
||
|
$success = NULL;
|
||
|
foreach ($groups as $groupID) {
|
||
|
$title = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $groupID, 'title');
|
||
|
if (array_key_exists($groupID, $contactGroups) && $contactGroups[$groupID]['status'] != 'Removed') {
|
||
|
$group[$groupID]['title'] = $contactGroups[$groupID]['title'];
|
||
|
|
||
|
$group[$groupID]['status'] = $contactGroups[$groupID]['status'];
|
||
|
$status = ts('You are already subscribed in %1, your subscription is %2.', array(
|
||
|
1 => $group[$groupID]['title'],
|
||
|
2 => ts($group[$groupID]['status']),
|
||
|
));
|
||
|
CRM_Utils_System::setUFMessage($status);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$se = self::subscribe($groupID,
|
||
|
$params['email'], $contactId, $context
|
||
|
);
|
||
|
if ($se !== NULL) {
|
||
|
$success = TRUE;
|
||
|
$groupAdded[] = $title;
|
||
|
|
||
|
// Ask the contact for confirmation
|
||
|
$se->send_confirm_request($params['email']);
|
||
|
}
|
||
|
else {
|
||
|
$success = FALSE;
|
||
|
$groupFailed[] = $title;
|
||
|
}
|
||
|
}
|
||
|
if ($success) {
|
||
|
$groupTitle = implode(', ', $groupAdded);
|
||
|
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)));
|
||
|
}
|
||
|
elseif ($success === FALSE) {
|
||
|
$groupTitle = implode(',', $groupFailed);
|
||
|
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)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|