406 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			406 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)));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
}
 |